uva1306 - The K-League 网络流

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 theremaining 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

  有N支队伍进行比赛,每支队伍需要打的比赛数目相同。每场比赛一个队伍胜,一个队伍败。给出每支队伍目前胜的场数和败的场数,以及每个队伍还剩下的比赛场数,输出所有可能得冠军的球队,可以并列。

  对于第i支队伍,让它在剩下的比赛中全部获胜,这时i获胜的总场数设为total,判断剩下队伍获胜场数是否能都不超过total。

  建图:对于每量支队伍(u,v)构造一个X节点,从S引一条弧容量为这两支队伍还需要比赛的场数。对每支队伍u构造一个Y节点,到T的容量为total-win(u),win(u)是已经获胜的场数。然后再把每个节点(u,v)到u和v各连一条弧,容量为INF。

  如果从S出发的所有弧满载说明队伍i能获得冠军。因为这时节点i到T可以满流,说明i剩下的场数可以全胜,并且可以找到对应的结果使其他队伍获胜的次数都不超过total。

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define eps 1e-9
#define INF 0x3f3f3f3f
#define MAXN 700
#define MAXM 55
#define MAXNODE 100010*4
#define MOD 999983
typedef long long LL;
using namespace std;
int T,N,w[30],d[30],a[30][30];

struct Edge{
    int from,to,cap,flow;
};
struct Dinic{
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> G[MAXN];
    bool vis[MAXN];
    int d[MAXN];
    int cur[MAXN];

    void clear_all(int n){
        for(int i=0;i<n;i++) G[i].clear();
        edges.clear();
    }
    void clear_nodes(int a,int b){
        for(int i=a;i<b;i++) G[i].clear();
    }
    void add_edge(int from,int to,int cap){
        edges.push_back((Edge){from,to,cap,0});
        edges.push_back((Edge){to,from,0,0});
        m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    bool BFS(){
        memset(vis,0,sizeof(vis));
        queue<int> q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            int len=G[x].size();
            for(int i=0;i<len;i++){
                Edge& e=edges[G[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int DFS(int x,int a){
        if(x==t||a==0) return a;
        int flow=0,f,len=G[x].size();
        for(int& i=cur[x];i<len;i++){
            Edge& e=edges[G[x][i]];
            if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edges[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }
    int maxflow(int s,int t,int limit){
        this->s=s;
        this->t=t;
        int flow=0;
        while(BFS()){
            memset(cur,0,sizeof(cur));
            flow+=DFS(s,limit-flow);
            if(flow==limit) break;
        }
        return flow;
    }
}g;

int ID(int u,int v){
    return u*N+v+1;
}
int ID(int u){
    return N*N+u+1;
}
bool win(int team){
    int total=w[team];
    for(int i=0;i<N;i++) total+=a[team][i];
    for(int i=0;i<N;i++) if(w[i]>total) return false;
    g.clear_all(N*N+N+2);
    int s=0,t=N*N+N+1,full=0;
    for(int u=0;u<N;u++){
        for(int v=u+1;v<N;v++){
            if(a[u][v]>0) g.add_edge(s,ID(u,v),a[u][v]);
            full+=a[u][v];
            g.add_edge(ID(u,v),ID(u),INF);
            g.add_edge(ID(u,v),ID(v),INF);
        }
        if(w[u]<total) g.add_edge(ID(u),t,total-w[u]);
    }
    return g.maxflow(s,t,full)==full;
}
int main(){
    freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        for(int i=0;i<N;i++) scanf("%d%d",&w[i],&d[i]);
        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++) scanf("%d",&a[i][j]);
        int first=1;
        for(int i=0;i<N;i++) if(win(i)){
            if(first) first=0;
            else printf(" ");
            printf("%d",i+1);
        }
        puts("");
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值