zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    To select the file to upload we can use the standard HTML input control of type
    Cascading Menu Script using Javascript Explained
    网站首页head区代码规范
    轻松掌握 Java 泛型
    JDK 5.0 中的泛型类型学习
    如何在firefox下获取下列框选中option的text
    是同步方法还是 synchronized 代码? 详解多线程同步规则
    javascript select option对象总结
    Select的动态取值(Text,value),添加,删除。兼容IE,FireFox
    javascript在ie和firefox下的一些差异
  • 原文地址:https://www.cnblogs.com/markliu/p/2540986.html
Copyright © 2011-2022 走看看