POJ-1087 二分图匹配,最大流。

来源:互联网 发布:参加java培训班有用吗 编辑:程序博客网 时间:2024/05/16 15:48

                                                  A Plug for UNIX

 题意很迷,不过很水。

 题意:一个房间有m个插座,每个插座有一个型号,现在有n台设备,每台设备指定了一种型号的插座,接下来有k个适配器,可以代替一种型号的插座。求最少有几台设备找不到插座。

 因为每个插座只能允许一台设备接入,所以很容易想到匹配问题,对,开始用二分图匹配写的成功AC,然后改成了最大流,发现最大流建图更容易,一波板子AC。但两种写法都涉及到传递闭包,还有题目有个很多小坑点,注意一下就好了。

  二分图:

const int N=800+10;int n,m,k,g[N][N],linked[N],used[N];void floyd(int num)//传递闭包{//    printf("%d\n",num);    for(int k=1; k<=num; k++)        for(int i=1; i<=num; i++)            for(int j=1; j<=num; j++)                g[i][j]=g[i][j]||(g[i][k]&&g[k][j]);//    for(int i=1;i<num;i++)//        for(int j=1;j<num;j++)//        printf("i=%d j=%d %d\n",i,j,g[i][j]);}bool dfs(int u){    for(int i=1; i<=m; i++)        if(!used[i]&&g[u][i])        {             used[i]=1;             if(linked[i]==-1||dfs(linked[i]))             {                 linked[i]=u;                 return true;             }        }        return false;}int hungary(){  int res=0;  memset(linked,-1,sizeof(linked));  for(int i=m+n+101;i<=m+n+101+n;i++)  {      memset(used,0,sizeof(used));      if(dfs(i)) res++;  }  return n-res;}int main(){    while(~scanf("%d",&m))    {        memset(g,0,sizeof(g));        map<string,int>q;        map<string,int>q1;        string plug,dev;        for(int i=1; i<=m; i++)        {            cin>>plug;            q[plug]=i;        }        scanf("%d",&n);        int tmpn=m+n+100,tmpm=m;        for(int i=1; i<=n; i++)        {            cin>>dev>>plug;            q1[dev]=++tmpn;            if(!q[plug]) q[plug]=++tmpm;            g[q1[dev]][q[plug]]=1;        }        scanf("%d",&k);        for(int i=1; i<=k; i++)        {            cin>>dev>>plug;            if(!q[dev]) q[dev]=++tmpm;            if(!q[plug]) q[plug]=++tmpm;            g[q[dev]][q[plug]]=1;//单向传递//            g[q[plug]][q[dev]]=1;        }        floyd(tmpn);        printf("%d\n",hungary());    }    return 0;}
 最大流:用0作为源点,与所有设备连边,容量为1,设备与对应型号插座连边,容量为1,别忘了传递闭包。插座和汇点连边,容量为1。注意,后出现的插座不能和汇点连边。
const int N=800+10;int n,m,k;int maze[N][N];int gap[N],dis[N],pre[N],cur[N];int flow[N][N];void floyd(int num)//电器与插头之间传递闭包{    for(int k=1; k<=num; k++)        for(int i=1; i<=num; i++)            for(int j=1; j<=num; j++)                maze[i][j]|=maze[i][k]&&maze[k][j];}int sap(int s,int t,int num){    memset(cur,0,sizeof(cur));    memset(dis,0,sizeof(dis));    memset(gap,0,sizeof(gap));    memset(flow,0,sizeof(flow));    int u=pre[s]=s,maxflow=0,aug=-1;    gap[0]=num;    while(dis[s]<num)    {loop:        for(int v=cur[u]; v<num; v++)            if(maze[u][v]-flow[u][v]&&dis[u]==dis[v]+1)            {                if(aug==-1||aug>maze[u][v]-flow[u][v]) aug=maze[u][v]-flow[u][v];                pre[v]=u;                u=cur[u]=v;                if(v==t)                {                    maxflow+=aug;                    for(u=pre[u]; v!=s; v=u,u=pre[u])                    {                        flow[u][v]+=aug;                        flow[v][u]-=aug;                    }                    aug=-1;                }                goto loop;            }        int mid=num-1;        for(int v=0; v<num; v++)            if(maze[u][v]-flow[u][v]&&mid>dis[v])            {                cur[u]=v;                mid=dis[v];            }        if((--gap[dis[u]])==0) break;        gap[dis[u]=mid+1]++;        u=pre[u];    }    return n-maxflow;}int main(){    while(~scanf("%d",&m))    {        string dev,plug;        map<string,int>q;        map<string,int>q1;        memset(maze,0,sizeof(maze));        //1-n为电器,101开始都是插头        //原点为0,汇点为301--最坏情况;        int num=100,hui=301;        for(int i=1; i<=m; i++)        {            cin>>plug;            q[plug]=++num;            maze[q[plug]][hui]=1;//插头到汇点的容量为1;        }        scanf("%d",&n);        for(int i=1; i<=n; i++)        {            cin>>dev>>plug;            q1[dev]=i;            maze[0][i]=1;//源点到电器,容量为1            if(!q[plug]) q[plug]=++num;            maze[i][q[plug]]=1;//电器到插头的容量为1;        }        scanf("%d",&k);        for(int i=1; i<=k; i++)        {            cin>>dev>>plug;            if(!q[dev]) q[dev]=++num;            if(!q[plug]) q[plug]=++num;            maze[q[dev]][q[plug]]=1;        }        floyd(300);        printf("%d\n",sap(0,301,302));    }    return 0;}


原创粉丝点击