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

                                                   A Plug for UNIX
閉包

 題意很迷,不過很水。oop

 題意:一個房間有m個插座,每一個插座有一個型號,如今有n臺設備,每臺設備指定了一種型號的插座,接下來有k個適配器,能夠代替一種型號的插座。求最少有幾臺設備找不到插座。ui

 由於每一個插座只能容許一臺設備接入,因此很容易想到匹配問題,對,開始用二分圖匹配寫的成功AC,而後改爲了最大流,發現最大流建圖更容易,一波板子AC。但兩種寫法都涉及到傳遞閉包,還有題目有個不少小坑點,注意一下就行了。spa

  二分圖:code

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;
}
相關文章
相關標籤/搜索