【LA2531 训练指南】足球联赛 【最大流】
题意:
有n支队伍进行比赛,每支队伍需要打的比赛数目相同。每场比赛恰好一支队伍胜,另一支败。给出每支队伍目前胜的场数和败的场数,以及每两支队伍还剩下的比赛场数,确定所有可能的冠军的球队。(获胜场数最多的是冠军,可以并列)。
分析
一只队伍如果可能得冠军,那么就一定可以通过调整,未来的几场比赛的结果使自己赢得场次最多。否则便不可能成为冠军。
在判断第i支队伍有无可能成为冠军时:首先,第i支队伍得对局i全部取得胜利,得到i胜利的总场数为total。然后判断其他队伍的对局,能否互相限制使得,任何队伍胜利的场数都不超过total。
建模方法:
对每两支队伍(u,v)构造一个X结点,从S引一条弧过来,容量为这两支队伍还需要比赛的场数。对每支队伍u构造一个Y结点,引一条弧到T,容量为total-win[u].然后每个(u,v)结点向u和v结点个连一条无穷大得弧。这样当且仅当,从S出发得每条弧都是满载得时候,当前队伍才有可能得冠军。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <queue> 6 #include <vector> 7 8 using namespace std; 9 const int maxn=1000+10; 10 const int MAXN=30; 11 const int maxm=30000+100; 12 const int INF=2147000000; 13 struct Dinic{ 14 int head[maxn],Next[maxm],to[maxm],cap[maxm],flow[maxm],from[maxm]; 15 int sz,n,m,s,t; 16 bool vis[maxn]; 17 int cur[maxn],d[maxn]; 18 void init(int n){ 19 this->n=n; 20 memset(head,-1,sizeof(head)); 21 this->sz=-1; 22 } 23 void add_edge(int a,int b,int c){ 24 ++sz; 25 to[sz]=b; 26 cap[sz]=c;flow[sz]=0;from[sz]=a; 27 Next[sz]=head[a];head[a]=sz; 28 ++sz; 29 to[sz]=a; 30 cap[sz]=c;flow[sz]=c;from[sz]=b; 31 Next[sz]=head[b];head[b]=sz; 32 } 33 bool BFS(){ 34 memset(vis,0,sizeof(vis)); 35 queue<int>Q; 36 vis[s]=1; 37 d[s]=0; 38 Q.push(s); 39 while(!Q.empty()){ 40 int u=Q.front();Q.pop(); 41 for(int i=head[u];i!=-1;i=Next[i]){ 42 int v=to[i]; 43 if(!vis[v]&&cap[i]>flow[i]){ 44 vis[v]=1; 45 d[v]=d[u]+1; 46 Q.push(v); 47 } 48 } 49 } 50 return vis[t]; 51 } 52 int DFS(int x,int a){ 53 if(x==t||a==0)return a; 54 int Flow=0,f; 55 for(int& i=cur[x];i!=-1;i=Next[i]){ 56 int v=to[i]; 57 if(d[v]==d[x]+1&&(f=DFS(v,min(a,cap[i]-flow[i])))>0){ 58 Flow+=f; 59 flow[i]+=f; 60 flow[i^1]-=f; 61 a-=f; 62 if(a==0)break; 63 } 64 } 65 return Flow; 66 } 67 int Maxflow(int s,int t){ 68 this->s=s,this->t=t; 69 int Flow=0; 70 while(BFS()){ 71 for(int i=0;i<=n;i++) 72 cur[i]=head[i]; 73 Flow+=DFS(s,INF); 74 } 75 return Flow; 76 } 77 }dinic; 78 int T,n; 79 int win[MAXN],lose[MAXN]; 80 int G[MAXN][MAXN]; 81 vector<int>ans; 82 bool judge(int num){ 83 int total=win[num]; 84 for(int i=1;i<=n;i++){ 85 total+=G[num][i]; 86 } 87 //cout<<total<<endl; 88 89 int allS=(n*n-3*n+2)/2; 90 int NUM=0; 91 dinic.init(allS+n+2); 92 dinic.s=0,dinic.t=allS+n+1; 93 for(int i=1;i<=n;i++){ 94 if(i==num)continue; 95 for(int j=i+1;j<=n;j++){ 96 // cout<<i<<" "<<j<<" "<<G[i][j]<<endl; 97 if(j==num)continue; 98 NUM++; 99 dinic.add_edge(0,NUM,G[i][j]); 100 dinic.add_edge(NUM,allS+i,INF); 101 dinic.add_edge(NUM,allS+j,INF); 102 } 103 } 104 105 for(int i=1;i<=n;i++){ 106 if(i==num)continue; 107 if(total<win[i])return false; 108 dinic.add_edge(allS+i,dinic.t,total-win[i]); 109 } 110 dinic.Maxflow(0,allS+n+1); 111 for(int i=0;i<=dinic.sz;i+=2){ 112 if(dinic.from[i]==0){ 113 if(dinic.flow[i]<dinic.cap[i]) 114 return false; 115 } 116 } 117 return true; 118 } 119 int main(){ 120 scanf("%d",&T); 121 for(int t=1;t<=T;t++){ 122 // if(t!=1)printf("\n"); 123 ans.clear(); 124 scanf("%d",&n); 125 for(int i=1;i<=n;i++){ 126 scanf("%d%d",&win[i],&lose[i]); 127 } 128 for(int i=1;i<=n;i++){ 129 for(int j=1;j<=n;j++){ 130 scanf("%d",&G[i][j]); 131 } 132 } 133 /* if(judge(1)) 134 printf("Yes 1");*/ 135 136 for(int i=1;i<=n;i++){ 137 if(judge(i)) 138 ans.push_back(i); 139 } 140 sort(ans.begin(),ans.end()); 141 for(int i=0;i<ans.size();i++){ 142 if(i!=0)printf(" "); 143 printf("%d",ans[i]); 144 } 145 printf("\n"); 146 } 147 return 0; 148 }