题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=33451
【思路】
最大流。
大体思路是枚举每个队伍,最大流判断是否可能成为冠军。
构图:
1 建立ST,比赛(u,v)建立n^2个结点,队伍u建立n个结点。
2 由S向(u,v)连容量为a[u][v]的边,由(u,v)向u和v连容量为INF的边,由u向T连容量为total-w[u]的边。
3 如果从S发出的边都满载则该team可行。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<vector> 5 #define FOR(a,b,c) for(int a=(b);a<(c);a++) 6 using namespace std; 7 8 const int maxn = 700+10; 9 const int INF = 1e9; 10 11 struct Edge{ 12 int u,v,cap,flow; 13 }; 14 struct Dinic { 15 int n,m,s,t; 16 bool vis[maxn]; 17 int d[maxn],cur[maxn]; 18 vector<int> G[maxn]; 19 vector<Edge> es; 20 21 void init(int n) { 22 this->n=n; 23 es.clear(); 24 for(int i=0;i<n;i++) G[i].clear(); 25 } 26 void AddEdge(int u,int v,int cap) { 27 es.push_back((Edge){u,v,cap,0}); 28 es.push_back((Edge){v,u,0,0}); 29 m=es.size(); 30 G[u].push_back(m-2); 31 G[v].push_back(m-1); 32 } 33 34 bool BFS() { 35 queue<int> q; 36 memset(vis,0,sizeof(vis)); 37 q.push(s); vis[s]=1; d[s]=0; 38 while(!q.empty()) { 39 int u=q.front(); q.pop(); 40 for(int i=0;i<G[u].size();i++) { 41 Edge& e=es[G[u][i]]; 42 int v=e.v; 43 if(!vis[v] && e.cap>e.flow) { 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 u,int a) { 53 if(u==t || a==0) return a; 54 int flow=0,f; 55 for(int& i=cur[u];i<G[u].size();i++){ 56 Edge& e=es[G[u][i]]; 57 int v=e.v; 58 if( d[v]==d[u]+1 && (f=DFS(v,min(a,e.cap-e.flow)))>0 ) { 59 e.flow+=f; 60 es[G[u][i]^1].flow-=f; 61 flow+=f,a-=f; 62 if(!a) 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 memset(cur,0,sizeof(cur)); 72 flow+=DFS(s,INF); 73 } 74 return flow; 75 } 76 } dc; 77 78 int n; 79 int w[maxn],d[maxn],a[maxn][maxn]; 80 81 int main() { 82 int T; 83 scanf("%d",&T); 84 while(T--) { 85 scanf("%d",&n); 86 for(int i=0;i<n;i++) scanf("%d%d",&w[i],&d[i]); 87 int sum=0; 88 for(int i=0;i<n;i++) 89 for(int j=0;j<n;j++) scanf("%d",&a[i][j]) , sum+=a[i][j]; 90 sum/=2; 91 int S=n*n+n , T=S+1; 92 bool first=1; 93 for(int team=0;team<n;team++) 94 { 95 int total=w[team]; 96 for(int i=0;i<n;i++) total+=a[team][i]; 97 bool flag=0; 98 for(int i=0;i<n;i++) if(w[i]>total) flag=1; //即使全胜依然不可能是冠军 99 if(flag) continue; 100 dc.init(n*n+n+2); 101 for(int i=0;i<n;i++) { 102 for(int j=i+1;j<n;j++) { 103 int r=i*n+j; 104 if(a[i][j]) dc.AddEdge(S,r,a[i][j]); 105 dc.AddEdge(r,n*n+i,INF) , dc.AddEdge(r,n*n+j,INF); 106 } 107 dc.AddEdge(n*n+i,T,total-w[i]); 108 } 109 if(dc.Maxflow(S,T)==sum) { 110 if(first) first=0; else putchar(' '); 111 printf("%d",team+1); 112 } 113 } 114 putchar(' '); 115 } 116 return 0; 117 }