POJ 1087 A Plug for UNIX 最大流

本题关键是建图,然后SAP水一个

建图:设0为源点,1为汇点,所以检索表里的插头下标要从2开始。

先输入n个插座,每个插座与汇点相连,值为1。

再输入m个用电器,用电器的名称其实是个无用的信息,把每个用电器的插头与源点相连,值为1。

然后输入k个转换器,如B X,则B与X连,注意值为INF(无穷大),因为这种类型的转换器可以有无数个。

最后SAP水一个,水题鉴定完毕。

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 100000000
#define maxn 405       //莫名其妙的RE,无奈开到405
#define maxm 305
int tot,head[maxn];
struct node
{
    int v, next ,c;
}edge[maxm * 2];    //双向别忘了*2;
int dis[maxn],num[maxn];
int cur[maxn],pre[maxn];
int n, m, k, s, t, vs;
void add(int x, int y, int c)
{
    edge[tot].v=y;
    edge[tot].c=c;
    edge[tot].next=head[x];
    head[x]=tot++;
    edge[tot].v=x;
    edge[tot].c=0;
    edge[tot].next=head[y];
    head[y]=tot++;
}
int cnt;
char id[maxn][40],s1[40],s2[40];
int sap()                  //sap非递归
{
    memset(dis,0,sizeof(dis));
    memset(num,0,sizeof(num));
    num[0]=vs=cnt;
    int i, u=pre[s]=s,aug=INF,v,maxf=0;     
    for(i=0;i<=cnt;i++)cur[i]=head[i];
    while(dis[s] < vs)
    {
loop:   for(i=head[u];i!=-1;i=edge[i].next)
        {
            v = edge[i].v;
            if(edge[i].c>0&&dis[u]==dis[v]+1)
            {
                aug=min(aug,edge[i].c);
                pre[v]=u;
                cur[u]=i;
                u=v;
                if(u == t)
                {
                    for(u=pre[u];v!=s;v=u,u=pre[u])
                    {
                        edge[cur[u]].c -= aug;
                        edge[cur[u]^1].c += aug;
                    }
                    maxf += aug;
                    aug=INF;
                }
                goto loop;
            }
        }
        int mind=vs;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            v = edge[i].v;
            if(dis[v]<mind&&edge[i].c>0)
            {
                mind=dis[v];
                cur[u]=i;
            }
        }
        if(!(--num[dis[u]]))break;
        ++num[dis[u]=mind+1];
        u=pre[u];
    }
    return maxf;
}
int find(char *s)    //建立检索表,找编号
{
    int i;
    for(i=2;i<cnt;i++)
        if(!strcmp(id[i],s))return i;
    strcpy(id[i],s);
    return cnt++;
}
int main()
{
    int i;
    while(~scanf("%d",&n))
    {
        cnt=2;s=0;t=1;                 //0为源点,1为汇点。
        memset(head,-1,sizeof(head));
        tot=0;
        for(i=1;i<=n;i++)
        {
            scanf("%s",s1);
            add(find(s1),t,1);
        }
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            scanf("%s%s",s1,s2);
            add(s,find(s2),1);
        }
        scanf("%d",&k);
        for(i=1;i<=k;i++)
        {
            scanf("%s%s",s1,s2);
            add(find(s1),find(s2),INF);//注意INF
        }
        printf("%d\n",m-sap());
    }
}

 

posted @ 2012-08-04 23:12  To be an ACMan  Views(236)  Comments(0)    收藏  举报