HDU 4265 Science! 网络流解多重匹配,输出所有比配可能

题意:给n个人,n个地方,每一轮每个人必须站到一个地方上,每个地方只能站一个人,这是一轮游戏,进行多轮,但是每一轮同一个人不能站在相同的地方上。


想法:这一题的第一步求出最大的游戏轮数和女生找男朋友那一题差不多,用二分+网络流即可得出解,剩下的部分就是找出这k种解,开始,我在原图的残余网络上直接找,每次找一组就标记一下输出,但是这样不对(不知为何),然后另一种方法就是比较笨的方法了,就是先把没有关系的边删除,然后找k次,每次跑一边网络流,s到个点的容量为1,这样就可以保证残留网络中有一组解,然后,输出这些解,然后删掉这一组解所对应的边,这样就OK了。

建边:

1.虚拟超级source和sink

2.source到每一个人连一条容量为k的边

3.每一个地方到sink连一条容量为k的边(2,3中的k在不同地方要进行不同的调整)

4.人与地方之间的关系连一条容量为1的边


#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define inf 0x7fffffff
using namespace std;
const int nodes=200;
const int edges=40000+50;
int n,s,t;
struct node
{
    int v,next,flow;
}e[edges];
int head[nodes],cur[nodes],cnt;
char map[nodes][nodes];
class Dinic
{
    public:
        int spath()
        {
            queue<int>q;
            while(!q.empty()) q.pop();
            memset(dis,-1,sizeof(dis));
            dis[s]=0;
            q.push(s);
            while(!q.empty())
            {
                int u=q.front();
                q.pop();
                for(int i=head[u];i+1;i=e[i].next)
                {
                    int v=e[i].v;
                    if(dis[v]==-1&&e[i].flow>0)
                    {
                        dis[v]=dis[u]+1;
                        q.push(v);
                    }
                }
            }
            return dis[t]!=-1;
        }
        int Min(int a,int b)
        {
            if(a<b) return a;
            return b;
        }
        int dfs(int u,int flow)
        {
            int cost=0;
            if(u==t) return flow;
            for(int &i=cur[u];i+1;i=e[i].next)
            {
                //cur[u]=i;
                int v=e[i].v;
                if(dis[v]==dis[u]+1&&e[i].flow>0)
                {
                    int minn=dfs(v,Min(e[i].flow,flow-cost));
                    if(minn>0)
                    {
                        e[i].flow-=minn;
                        e[i^1].flow+=minn;
                        cost+=minn;
                        if(cost==flow) break;
                    }
                    else dis[v]=-1;
                }
            }
            return cost;
        }
        int result()
        {
            int xx=0;
            while(spath())
            {
                for(int i=s;i<=t;i++) cur[i]=head[i];
                xx+=dfs(s,inf); 
            }
            return xx;
        }
    private:
        int dis[nodes];
}dinic;
void Init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
}
void add(int a,int b,int c)
{
    e[cnt].v=b;
    e[cnt].next=head[a];
    e[cnt].flow=c;
    head[a]=cnt++;
    
    e[cnt].v=a;
    e[cnt].flow=0;
    e[cnt].next=head[b];
    head[b]=cnt++;
}
void build_map(int val)
{
    Init();
    for(int i=1;i<=n;i++)
    {
        add(s,i,val);
        add(i+n,t,val);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(map[i][j]=='Y')
            {
                add(i,j+n,1);
            }
        }
    }
}
int find_mid()
{
    int low=0,up=n,ans=0;
    while(low<=up)
    {
        int mid=(low+up)>>1;
        build_map(mid);
        if(dinic.result()==mid*n)
        {
            ans=mid;
            low=mid+1;
        }
        else up=mid-1;
    }
    return ans;
}
void find_one_ans_del()
{
    int res[nodes];
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j+1;j=e[j].next)
        {
            int v=e[j].v;
            if(v!=s&&!e[j].flow)
            {
                res[v-n]=i;
                map[i][v-n]='N';
                break;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(i==1) printf("%d",res[i]);
        else printf(" %d",res[i]);
    }
    printf("\n");
    /*for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j+1;j=e[j].next)
        {
            int v=e[j].v;
            if(v!=s&&e[j].flow==0)
            {
                map[i][v-n]='N';
                break;
            }
        }
    }*/
}
void treatment(int rmid)
{
    printf("%d\n",rmid);
    build_map(rmid);
    dinic.result();
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j+1;j=e[j].next)
        {
            int v=e[j].v;
            if(v!=s&&e[j].flow==1)
            {
                map[i][v-n]='N';
            }
        }
    }
    while(rmid--)
    {
        build_map(1);
        dinic.result();
        find_one_ans_del();
    }
}
int main()
{
    while(~scanf("%d",&n),n)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%s",map[i]+1);
        }
        s=0;t=2*n+1;
        int kr=find_mid();
        treatment(kr);
    }
    return 0;
} 

你可能感兴趣的:(HDU 4265 Science! 网络流解多重匹配,输出所有比配可能)