【Uvalive 2531】 The K-League (最大流-类似公平分配问题)

【题意】

  有n个队伍进行比赛,每场比赛,恰好有一支队伍取胜、一支队伍败。每个队伍需要打的比赛场数相同,给你每个队伍目前已经赢得场数和输得场数,再给你一个矩阵,第 i 行第 j 列 表示队伍 i 和队伍 j 还需要打的比赛数,问你哪些队伍有可能获得冠军(胜场最多的即为冠军,可以并列)。

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 ≤ n ≤ 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 n
2 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

 

 

【分析】

  枚举判断每个队伍是否可以是冠军。

  然后贪心的思想,想让他在接下来的比赛中全部获胜,接下来只用判断其他队伍的比赛是否可以相互制约,使得枚举的是总冠军。

  st->(u,v),表示比赛,流量为比场数。

  (u,v)->u (u,v)->v 流量为INF

  u->ed 流量为tot-w[u] ,tot为枚举的那个的现在计算出的胜利场数,如果他是冠军,那么其他队伍的胜利场数不能超过他。

  跑最大流,然后判断st->xxx 是否满流。

 

  这题跟公平分配问题是相似的模型。

  把每场比赛看成“任务”,每支队伍看成“处理器”,tot是制约(相当于我们二分的答案)。

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 30
  9 #define Mn 1010
 10 #define INF 0xfffffff
 11 
 12 struct node
 13 {
 14     int x,y,f,o,next;
 15 }t[Mn*4];
 16 int len,first[Mn];
 17 
 18 int mymin(int x,int y) {return x<y?x:y;}
 19 
 20 void ins(int x,int y,int f)
 21 {
 22     if(f<=0) return;
 23     t[++len].x=x;t[len].y=y;t[len].f=f;
 24     t[len].next=first[x];first[x]=len;t[len].o=len+1;
 25     t[++len].x=y;t[len].y=x;t[len].f=0;
 26     t[len].next=first[y];first[y]=len;t[len].o=len-1;
 27 }
 28 
 29 int w[Maxn],d[Maxn],a[Maxn][Maxn];
 30 int n;
 31 
 32 void init()
 33 {
 34     scanf("%d",&n);
 35     for(int i=1;i<=n;i++)
 36     {
 37         scanf("%d%d",&w[i],&d[i]);
 38     }
 39     for(int i=1;i<=n;i++)
 40      for(int j=1;j<=n;j++)
 41      scanf("%d",&a[i][j]);
 42     for(int i=1;i<=n;i++)
 43     {
 44         a[i][0]=0;
 45         for(int j=1;j<=n;j++) a[i][0]+=a[i][j];
 46     }
 47 }
 48 
 49 int dis[Mn],st,ed;
 50 queue<int > q;
 51 bool bfs()
 52 {
 53     while(!q.empty()) q.pop();
 54     memset(dis,-1,sizeof(dis));
 55     q.push(st);dis[st]=0;
 56     while(!q.empty())
 57     {
 58         int x=q.front();
 59         for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 60         {
 61             int y=t[i].y;
 62             if(dis[y]==-1)
 63             {
 64                 dis[y]=dis[x]+1;
 65                 q.push(y);
 66             }
 67         }
 68         q.pop();
 69     }
 70     if(dis[ed]==-1) return 0;
 71     return 1;
 72 }
 73 
 74 int ffind(int x,int flow)
 75 {
 76     if(x==ed) return flow;
 77     int now=0;
 78     for(int i=first[x];i;i=t[i].next) if(t[i].f>0)
 79     {
 80         int y=t[i].y;
 81         if(dis[y]==dis[x]+1)
 82         {
 83             int a=ffind(y,mymin(flow-now,t[i].f));
 84             t[i].f-=a;
 85             t[t[i].o].f+=a;
 86             now+=a;
 87         }
 88         if(now==flow) break;
 89     }
 90     if(now==0) dis[x]=-1;
 91     return now;
 92 }
 93 
 94 int max_flow()
 95 {
 96     int ans=0;
 97     while(bfs())
 98     {
 99         ans+=ffind(st,INF);
100     }
101     return ans;
102 }
103 
104 int main()
105 {
106     int T;
107     scanf("%d",&T);
108     while(T--)
109     {
110         init();
111         bool op=0;
112         for(int i=1;i<=n;i++)
113         {
114             int tot=a[i][0]+w[i],cnt,sum=0;
115             len=0;
116             memset(first,0,sizeof(first));
117             st=n+1,ed=st+1,cnt=ed;
118             bool ok=1;
119             for(int j=1;j<=n;j++) if(j!=i)
120             {
121                 ins(j,ed,tot-w[j]);
122                 if(tot-w[j]<0) ok=0;
123             }
124             for(int j=1;j<=n;j++) if(j!=i)
125              for(int k=j+1;k<=n;k++) if(k!=i)
126              {
127                  sum+=a[j][k];
128                 ins(st,++cnt,a[j][k]),ins(cnt,j,INF),ins(cnt,k,INF);
129              }
130             int x=max_flow();
131             if(x!=sum) ok=0;
132             if(ok)
133             {
134                 if(op) printf(" ");
135                 op=1;
136                 printf("%d",i);
137             }
138         }
139         // if(T) 
140             printf("\n");
141     }
142     return 0;
143 }
View Code

 

输出文件末不输出空行是WA,行末有空格是PE,也是。。

 

2016-11-04 07:47:58

转载于:https://www.cnblogs.com/Konjakmoyu/p/6028957.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值