2011东北地区赛G题(二分网络流判可行性)

题意:从M个参赛选手中选一些人参加N轮比赛,每场比赛只能有一个人胜出,问如何安排比赛,让获胜最多的那个人获胜次数最少。

构图:二分次数,用最大流判可行性。

源点向参赛人员连容量为该参赛人员最多获胜次数的边,二分限制参赛人员的最多获胜次数;

比赛向汇点连容量为每场比赛最多有几人胜出的边;

参赛人员分别向自己所参加的比赛连容量为1的边。

View Code
/*Source Code
Problem: 1003
Username: 2010201211
Run Time: 736MS
Memory: 1084K
Language:C++
JudgeStatus: Accepted*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
#define E 60000
#define V 700
#define inf 0x3F3F3F3F
struct Edge
{
    int u,v,c,next;
}edge[E*2];
int cnt;
int dist[V];
int head[V];
int que[V];
int sta[V];

void init(){
    cnt=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int c){
    edge[cnt].u=u;edge[cnt].v=v;edge[cnt].c=c;
    edge[cnt].next=head[u];head[u]=cnt++;

    edge[cnt].u=v;edge[cnt].v=u;edge[cnt].c=0;
    edge[cnt].next=head[v];head[v]=cnt++;
}

int dinic(int s,int t){
    int ans=0;
    while(true){
        int left,right,u,v;

        memset(dist,-1,sizeof(dist));
        left=right=0;
        que[right++]=s;
        dist[s]=0;

        while(left<right){//bfs构造层次网络
            u=que[left++];
            for(int k=head[u];k!=-1;k=edge[k].next){
                u=edge[k].u;
                v=edge[k].v;
                if(edge[k].c>0 && dist[v]==-1){
                    dist[v]=dist[u]+1;
                    que[right++]=v;
                    if(v==t){
                        left=right;
                        break;
                    }
                }
            }
        }

        if(dist[t]==-1) break;//汇点不在层次网络中,算法结束.

        int top=0;
        int now=s;

        while(true){//层次图中进行一次dfs增广
            if(now!=t){//dfs未到汇点
                int k;
                for(k=head[now];k!=-1;k=edge[k].next){//判断now之后是否有可用点(入度是否为0)
                    if(edge[k].c>0 && dist[edge[k].u]+1==dist[edge[k].v]) break;
                }
                if(k!=-1){//如果now之后有可用点(入度>0)
                    //cout << top << endl;
                    sta[top++]=k;//边入栈
                    now=edge[k].v;
                }
                else{//now之后没有可用点
                    if(top==0) break;
                    dist[edge[sta[--top]].v]=-1;//从p和层次图中删除点u以及u连接的所有边

                    now=edge[sta[top]].u;
                }

            }
            else{//dfs到汇点
                int flow=inf,ebreak;
                //(1)增广p
                for(int i=0;i<top;i++){
                    if(flow>edge[sta[i]].c){
                        flow=edge[sta[i]].c;
                        ebreak=i;
                    }
                }
                ans+=flow;
                for(int i=0;i<top;i++){
                    edge[sta[i]].c-=flow;//正向边减流
                    edge[sta[i]^1].c+=flow;//反向边加流
                }

                //(2)退至p中从源点可到达的最后一个顶点
                now=edge[sta[ebreak]].u;
                top=ebreak;
            }
        }

    }
    return ans;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n,m,k,cptor[105],a,map[505][105];
    while(scanf("%d%d",&n,&m)!=EOF){
        memset(cptor,0,sizeof(cptor));
        memset(map,0,sizeof(map));
        for(int i=1;i<=n;i++){
            scanf("%d",&k);
            for(int j=1;j<=k;j++){
                scanf("%d",&a);
                map[i][a]=1;
                cptor[a]++;
            }
        }
        int maxc=-1;
        for(int i=1;i<=m;i++){
            maxc=max(maxc,cptor[i]);
        }
        int mid,log=0;
        int left=0,right=maxc+1;

        while(left<right){
            mid=(left+right)/2;
            init();
            for(int i=1;i<=m;i++){
                if(cptor[i]>mid) addedge(0,i,mid);
                else addedge(0,i,cptor[i]);
                for(int j=1;j<=n;j++){
                    if(map[j][i]==1){
                        addedge(i,m+j,1);
                    }
                }
            }
            for(int i=1;i<=n;i++){
                addedge(m+i,m+n+1,1);
            }

            int res=dinic(0,m+n+1);
            if(res==n) {
                right=mid;
                log=mid;
            }
            else left=mid+1;
        }
        printf("%d\n",log);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/markliu/p/2540986.html