zoukankan      html  css  js  c++  java
  • la 2531 uva 1306 isap / Dinic 最大流

    Supporters for the professional soccer clubs participating in the K-League, formerly the Korea Professional Soccer League, hold orderly and organized cheering, as did the Red Devils, the official supporters for the Korean national soccer team during the 2002 Korea-Japan World Cup. After many games of this season have been played, the supporters may wonder whether the team S they are backing can still win the championship. In other words, can winners be assigned for the remaining games so that no team ends with more victories than S ? Two or more teams can win the championship jointly.


    You are given the current number of wins and defeats, wi and di , for every team i , 1$ le$i$ le$n , and the remaining number, ai, j , of games to be played between every pair of teams i and j , 1$ le$i, j$ le$n , where n is the number of teams. The teams are numbered 1, 2,..., n . You are to find all teams that have a possibility of winning the championship. Every team has to play the same number games during the season. For simplicity, we assume that there are no draws, that is, every game has a winner and a loser.

    Input 

    The input consists of T test cases. The number of test cases (T) is given in the first line of the input file.


    Each test case consists of three lines: the first line has an integer n ( 1$ le$n$ le$25 ), that represents the number of teams in the test case; the second line contains 2n nonnegative integers w1, d1, w2, d2,..., wn, dn , each at most 100, where wi and di are the current numbers of wins and defeats for team i , respectively; the third line contains n2 nonnegative integers a1, 1, a1, 2,..., a1, n, a2, 1, a2, 2,..., a2, n, ... , an, 1, an, 2,..., an, n , each at most 10, where ai, j is the remaining number of games to be played between teams i and j . For all i and j , ai, j is equal to aj, i . If i = j , then ai, j = 0 . The integers given in a line are delimited by one or more spaces.

    Output 

    Print exactly one line for each test case. The line should contain all teams that have a possibility of winning the championship, in an increasing order of team numbers.

    Sample Input 

    3                                                   
    3                                                   
    2 0 1 1 0 2                                         
    0 2 2 2 0 2 2 2 0 
    3 
    4 0 2 2 0 4 
    0 1 1 1 0 1 1 1 0 
    4 
    0 3 3 1 1 3 3 0 
    0 0 0 2 0 0 1 0 0 1 0 0 2 0 0 0
    

    Sample Output 

    1 2 3 
    1 2 
    2 4
    
    看的白书,建模方式如下:
    加虚拟源汇s,t,类似二分图,X中点为(u, v)表示u, v间的比赛, Y中节点为各个队u。 从s向X中节点各连一条弧,容量为比赛场数, 从(u, v)向u,v分别连一条弧,容量无限大(?),从u向t连一条弧,容量为假设队i赢剩余所有比赛
    (设为n场)时,队u赢不超过n场比赛的最大值,即n-w[u],w[u]表示队u已经赢了多少比赛。
    用Dinic, ISAP AC了,AC代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    
    using namespace std;
    
    #define LL long long
    #define ULL unsigned long long
    #define UINT unsigned int
    #define MAX_INT 0x7fffffff
    #define MAX_LL 0x7fffffffffffffff
    #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
    #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
    #define INF 10000000
    #define MAXN 356
    #define MAXM 2222
    #define MAXT 27
    
    struct edge{
        int u, v, cap, flow, nxt;
    }e[MAXM];
    int h[MAXN], cc;
    
    int a[MAXT][MAXT], w[MAXT];
    
    void add(int u, int v, int cap){
        e[cc]=(edge){u, v, cap, 0, h[u]};
        h[u]=cc++;
        e[cc]=(edge){v, u, 0,   0, h[v]};
        h[v]=cc++;
    }
    
    int cur[MAXN], d[MAXN];
    
    bool done[MAXN];
    void bfs(int t){                                     //reverse bfs
        queue<int> q;
        memset(done, 0, sizeof(done));  done[t]=true;
        d[t]=0;         q.push(t);
        while(!q.empty()){
            int u=q.front();    q.pop();
            for(int i=h[u]; i!=-1; i=e[i].nxt){
                int v=e[i^1].u, flow=e[i^1].flow, cap=e[i^1].cap;   //attention 'u'
                if(cap>flow && !done[v]){
                    done[v]=true;
                    d[v]=d[u]+1;
                    q.push(v);
                }
            }
        }
    }
    
    int num[MAXN], p[MAXN];
    
    int Augment(int s, int t){                          //similar to Edmonds-Karp
        int u=t, a=INF;
        while(u!=s){
            a=MIN(a, e[p[u]].cap-e[p[u]].flow);
            u=e[p[u]].u;
        }
        for(u=t; u!=s; u=e[p[u]].u){
            e[p[u]].flow+=a;
            e[p[u]^1].flow-=a;
        }
        return a;
    }
    int isap(int s, int t){
        int flow=0, i;
        bfs(t);
        memset(num, 0, sizeof(num));
        for(i=0; i<t+1; i++) num[d[i]]++;
        int u=s;
        for(i=0; i<t+1; i++) cur[i]=h[i];
        while(d[s]<t+1){
            if(u==t){
                flow+=Augment(s, t);
                u=s;
            }
            bool ok=false;
            for(int i=cur[u]; i!=-1; i=e[i].nxt){           //advance
                int v=e[i].v, flow=e[i].flow, cap=e[i].cap;
                if(cap>flow && d[u]==d[v]+1){
                    ok=true;
                    p[v]=i;
                    cur[u]=i;
                    u=v;
                    break;
                }
            }
            if(!ok){                                    //retreat
                int tmp=t;
                for(int i=h[u]; i!=-1; i=e[i].nxt) if(e[i].cap>e[i].flow)
                    tmp=MIN(tmp, d[e[i].v]);
                if(--num[d[u]]==0) break;               //gap improvement
                num[d[u]=tmp+1]++;
                cur[u]=h[u];
                if(u!=s) u=e[p[u]].u;
            }
        }
        return flow;
    }
    int n;
    bool ok(int teami){
        int i, j, full=0, k=n+1;
        const int s=0, t=(n*n+n)/2+1;
        int total=w[teami], mx=0;
        for(i=1; i<=n; i++){
            mx=MAX(mx, w[i]);
            total+=a[teami][i];
        }
        if(total<mx) return false;
        memset(h, -1, sizeof(h));       cc=0;
        for(i=1; i<=n; i++){
            for(j=1+i; j<=n; j++){
                add(k, i, INF);                     //(u, v)到u
                add(k, j, INF);                     //(u, v)到v
                if(a[i][j]>0) add(s, k, a[i][j]);     //s到(u, v)
                full+=a[i][j];
                k++;
            }
            if(total>w[i]) add(i, t, total-w[i]);
        }
        return full==isap(s, t);
    }
    
    int main(){
        int T;
        scanf(" %d", &T);
        while(T--){
            int i, j, l;
            scanf(" %d", &n);
            for(i=1; i<=n; i++) scanf(" %d %d", w+i, &l);
            for(i=1; i<=n; i++)
                for(j=1; j<=n; j++)
                    scanf(" %d",&a[i][j]);
    
            bool first=true;
            for(i=1; i<=n; i++) if(ok(i)){
                if(!first) printf(" %d", i);
                else printf("%d", i), first=false;
            }
            printf("
    ");
        }
        return 0;
    }
    

     Dinic:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<cstdlib>
    #include<algorithm>
    #include<queue>
    
    using namespace std;
    
    #define LL long long
    #define ULL unsigned long long
    #define UINT unsigned int
    #define MAX_INT 0x7fffffff
    #define MAX_LL 0x7fffffffffffffff
    #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
    #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
    #define INF 10000000
    #define MAXN 700
    #define MAXM 2222
    #define MAXT 27
    
    struct edge{
        int u, v, cap, flow, nxt;
    }e[MAXM];
    int h[MAXN], cc;
    
    int a[MAXT][MAXT], w[MAXT], l[MAXT];
    
    void add(int u, int v, int cap){
        e[cc]=(edge){u, v, cap, 0, h[u]};
        h[u]=cc++;
        e[cc]=(edge){v, u, 0,   0, h[v]};
        h[v]=cc++;
    }
    
    int cur[MAXN], d[MAXN];
    
    bool vis[MAXN];
    bool bfs(int s, int t){
        queue<int> q;
        memset(vis, 0, sizeof(vis));
        d[s]=0;     vis[s]=true;
        q.push(s);
        while(!q.empty()){
            int u=q.front();    q.pop();
            for(int i=h[u]; i!=-1; i=e[i].nxt){
                int v=e[i].v, cap=e[i].cap, flow=e[i].flow;
                if(!vis[v] && cap>flow){
                    vis[v]=true;
                    d[v]=d[u]+1;
                    q.push(v);
                }
            }
        }
        return vis[t];
    }
    
    int dfs(int u, int a, int t){
        if(u==t || a==0) return a;
        int flow=0, f;
        for(int &i=cur[u]; i!=-1; i=e[i].nxt){
            int v=e[i].v, cap=e[i].cap, ef=e[i].flow;
            if(d[v]==d[u]+1 && (f=dfs(v, MIN(a, cap-ef), t))>0){
                flow+=f;
                e[i].flow+=f;
                e[i^1].flow-=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }
    
    int Dinic(int s, int t){
        int flow=0;
        while(bfs(s, t)){
            for(int i=s; i<=t; i++) cur[i]=h[i];
            flow+=dfs(s, INF, t);
        }
        return flow;
    }
    int n;
    
    inline int ID(int u, int v) { return u*n+v+1; }
    inline int ID(int u) { return n*n+u+1; }
    
    int hsh[MAXN][MAXN];
    void handle(){
        int k=1+n;
        for(int i=1; i<=n; i++)
            for(int j=1+i; j<=n; j++)
                hsh[j][i]=hsh[i][j]=k++;
    //    cout<<"hash k="<<k<<endl;
    }
    
    inline int MID(int u){ return u;}
    inline int MID(int u, int v){ return hsh[u][v];}
    
    bool ok(int teami){
        int i, j, full=0;
        const int s=0, t=(n*n+n)+1;
        int total=w[teami], mx=0;
        for(i=1; i<=n; i++){
            mx=MAX(mx, w[i]);
            total+=a[teami][i];
        }
        if(total<mx) return false;
        memset(h, -1, sizeof(h));       cc=0;
        for(i=1; i<=n; i++){
            for(j=1+i; j<=n; j++){
                add(ID(i-1, j-1), ID(i-1), INF);                     //(u, v)到u
                add(ID(i-1, j-1), ID(j-1), INF);                     //(u, v)到v
                if(a[i][j]>0) add(s, ID(i-1, j-1), a[i][j]);     //s到(u, v)
                full+=a[i][j];
            }
            if(total>w[i]) add(ID(i-1), t, total-w[i]);
        }
        return full==Dinic(s, t);
    }
    
    int main(){
    //    freopen("C:\Users\Administrator\Desktop\in.txt","r",stdin);
        int T;
        scanf(" %d", &T);
        while(T--){
            int i, j;
            scanf(" %d", &n);           handle();
            for(i=1; i<=n; i++) scanf(" %d %d", w+i, l+i);
            for(i=1; i<=n; i++)
                for(j=1; j<=n; j++)
                    scanf(" %d",&a[i][j]);
    
            bool first=true;
            for(i=1; i<=n; i++) if(ok(i)){
                if(!first) printf(" %d", i);
                else printf("%d", i), first=false;
            }
            printf("
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    如何利用InstallShield for Delphi7打包Oracle9i客户端制作C/S数据库应用程序?
    delphi 保存 和 打开 TREE VIEW的节点已经展开的状态
    在Delphi中的TreeView中保存多个数据
    FastReport经验
    农码一生博文索引
    再讲IQueryable<T>,揭开表达式树的神秘面纱
    你知道C#中的Lambda表达式的演化过程吗?
    先说IEnumerable,我们每天用的foreach你真的懂它吗?
    Linq表达式、Lambda表达式你更喜欢哪个?
    你必须知道的EF知识和经验
  • 原文地址:https://www.cnblogs.com/ramanujan/p/3330149.html
Copyright © 2011-2022 走看看