现在的位置: 首页 > 综合 > 正文

poj 1087 A Plug of UNIX Dinic邻接表算法解决

2017年10月18日 ⁄ 综合 ⁄ 共 2656字 ⁄ 字号 评论关闭

    这个题目纠结的我要死。。。

   首先是最大流的第一次应用,  我一直认为是求最大流那错了。。。

  事实上,那里确实出错了一次。。。不过,那也无关紧要,主要是对那个字符串的处理,即将题目给的输入转化成一个图。

   这个过程,我仍然没有完全的清楚。所以导致了卡的太久。。。

   这个题,开始我自己想的时候,是想到了二分图,其实二分图,也差不多。

    最主要,最关键的还是建图。。。这个图你转化不过来的话,没搞手,,

   所以我觉得这个题,要分析的透彻了之后再动手打代码。。  不然你真的会付出代价的。。

    这个透彻是要全部理解了。。。

  首先,理解由多源点多汇点图,转化成单源单汇图。 N=(V,X,Y,A,C)  ==>  N=(V,s,t,A,C)。源点都在X集合里,汇点都在Y集合里。这样的一个S(X,Y)称为N的一个割。

   建立 s到X 集合里所有点的边 和 Y集合里的点到 t 的所有边。边上的权值等下说。

   s,t 称为人工源和人工汇,这个我们可以自己设置。

  到这里我们要将图建成功的话,就必须要知道X,Y这两个集合,以及X,Y两个集合之间的边。

  先来建立Y集合。

  Y集合的话也就是房间里的各个插座,将每个插座按输入的顺序标上序号。然后连上汇点 t。  边权都为1 。 因为近来一个就说明有一个被用了。最多也就那么多个。所以都是1

  X集合就是每个用电器的插座的名字,接着上面的序号按照输入顺序标号,这里要注意,假如某个用电器的插头是房间里有的,就直接用上面的已经标了的序号。 如果房间里没有对应的插座,那么就接着上面的序号按照输入的顺序标号,然后让s 与这些用电器的插头的序号 连接上,边权值就是这个插头出现的次数。

  最后就是X, Y 集合之间的边了。。 

  假如在名字和上面出现的有相同的,那么就用那个插头的序号。否则,继续接着上面的那个序号按输入顺序标号。然后将两个点连接起来,边权设为无穷大

到此为止,图建好了。

  然后直接求最大流就可以了。  几乎是一道最大流的模板题。

下面贴代码:

Source Code

Problem: 1087  User: 201141919106 
Memory: 344K  Time: 0MS 
Language: C  Result: Accepted 

Source Code 
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define N 403
#define Z N
#define INF 0x7fffffff

int V[N];
int d[N];
int next[N*3];
int cap[N*3];
int path[N];
int E[N*3];
int S,T,M;

void init(int from,int to,int c)
{
    M++;
    cap[M]=c;
    E[M]=to;
    next[M]=V[from];
    V[from]=M;
}

void insert(int from,int to,int c)
{
    init(from,to,c);
    init(to,from,0);
}

int bfs()
{
    int queue[N];
    int f,t;
    int x,i,y;
    f=t=0;
    memset(d,0,sizeof(d));
    queue[t++]=S;
    d[S]=1;
    while(f!=t)
    {
        x=queue[f++];
        for(i=V[x]; i; i=next[i])
        {
            y=E[i];
            if(cap[i]>0&&d[y]==0)
            {
                d[y]=d[x]+1;
                if(y==T)
                {
                    return 1;
                }
                queue[t++]=y;
            }
        }
    }
    return 0;
}

int dfs()
{
    int i,t,back,u,y;
    int maxFlow=0;
    int min;
    t=1;
    while(t)
    {
        u=(t==1)?S:E[path[t-1]];
        if(u==T)
        {
            min=INF;
            for(i=1; i<t; i++)
            {
                if(cap[path[i]]<min)
                {
                    min=cap[path[i]];
                    back=i;
                }
            }
            for(i=1; i<t; i++)
            {
                cap[path[i]]-=min;
                cap[path[i]+1]+=min;
            }
            maxFlow+=min;
            t=back;
        }
        else
        {
            for(i=V[u]; i; i=next[i])
            {
                y=E[i];
                if(cap[i]>0&&(d[y]==d[u]+1))break;
            }
            if(i)
            {
                path[t++]=i;
            }
            else
            {
                d[u]=0;
                t--;
            }
        }
    }

    return maxFlow;
}

int dinic()
{
    int maxFlow=0;
    while(bfs())
    {
        maxFlow+=dfs();
    }
    return maxFlow;
}
int main()
{
    int n,m,j,q,r,i,c;
    char s[Z][Z],str[Z],ch[Z];
    int p[Z];
    while(~scanf("%d\n",&n))
    {
        M=0;
        S=0;
        T=N-1;
        memset(V,0,sizeof(V));
        memset(p,0,sizeof(p));
        memset(E,0,sizeof(E));
        memset(cap,0,sizeof(cap));
        memset(next,0,sizeof(next));
        memset(s,0,sizeof(s));
        memset(str,0,sizeof(str));
        memset(ch,0,sizeof(ch));
        for(i=1; i<=n; i++)
        {
            scanf("%s",s[i]);
            insert(i,T,1);
        }
        c=n;
        scanf("%d\n",&m);
        for(i=0; i<m; i++)
        {
            scanf("%s %s",str,ch);
            for(j=1; j<=c; j++)
            {
                if(strcmp(s[j],ch)==0)
                {
                    p[j]++;
                    break;
                }
            }
            if(j>c)
            {
                strcpy(s[++c],ch);
                p[c]++;
            }
        }
        scanf("%d\n",&r);
        for(i=1; i<=r; i++)
        {
            scanf("%s%s",str,ch);
            for(j=1; j<=c; j++)
            {
                if(strcmp(s[j],str)==0)
                {
                    break;
                }
            }
            if(j>c)
            {
                strcpy(s[++c],str);
            }
            for(q=1; q<=c; q++)
            {
                if(strcmp(s[q],ch)==0)
                {
                    break;
                }
            }
            if(q>c)
            {
                strcpy(s[++c],ch);
            }
            insert(j,q,INF);
        }
        for(i=1; i<=c; i++)
        {
            insert(S,i,p[i]);
        }
        printf("%d\n",m-dinic());
    }
    return 0;
}

抱歉!评论已关闭.