题意:n个队比赛,给出每个队当前的胜场和负场,给出接下来各队伍间比赛场数,求都有哪支队伍能够赢得冠军(可以并列)。
思路:可以假设每个队接下来的比赛全胜,在看这支队伍是否能获胜。对于其他队伍之间的比赛来说,可以看成一个分配问题,即把接下来除假定队伍外,每场比赛的胜场分配给相应队伍,使得每个队伍获胜总场数不超过假设队伍。这样的话,添加一个源点,从源点向每场比赛连一条边,容量为比赛场数,然后从每场比赛向两个比赛队伍各连一条边,容量为无穷大,最后,从每个队伍向汇点连一条边,容量为该队伍还能获得的最大胜场。求最大流,若从S出发的弧满载,那么说明该队伍可以获胜。
可以参考一下Matrix67的一篇文章:http://www.matrix67.com/blog/archives/5190
代码:
#include <iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #define inf 2139062143 #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; const int maxn=1000; struct Edge { int from,to,cap,flow; }; struct Dinic { vector<Edge>edges; vector<int>G[maxn]; int m,n,s,t; int cur[maxn],d[maxn]; bool vis[maxn]; void ClearAll(int n) { for(int i=0;i<=n;++i) G[i].clear(); edges.clear(); } void AddEdges(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]=true; while(!q.empty()) { int x=q.front();q.pop(); for(int i=0;i<G[x].size();++i) { Edge e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow) { vis[e.to]=true; 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; for(int &i=cur[x];i<G[x].size();++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) { edges[G[x][i]].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) { this->s=s;this->t=t; int flow=0; while(BFS()) { memset(cur,0,sizeof(cur)); flow+=DFS(s,inf); } return flow; } }dinic; int games[30][30],wins[30],ans[30]; bool canwin(int N,int w,int n) { dinic.ClearAll(N); int total=0,temp=0; for(int i=1;i<=n;++i) total+=games[w][i]; total+=wins[w]; for(int i=1;i<=n;++i) { if(i==w) continue; if(wins[i]>total) return false; dinic.AddEdges(i,N,total-wins[i]); } int p=0; for(int i=1;i<=n;++i) { if(i==w) continue; for(int j=i+1;j<=n;++j) { if(j==w) continue; p++; dinic.AddEdges(0,p+n,games[i][j]); temp+=games[i][j]; dinic.AddEdges(p+n,i,inf); dinic.AddEdges(p+n,j,inf); } } return dinic.Maxflow(0,N)==temp; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t,n; scanf("%d",&t); while(t--) { scanf("%d",&n); int N=n*n+n; int a,b; for(int i=1;i<=n;++i) { scanf("%d%d",&a,&b); wins[i]=a; } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) scanf("%d",&games[i][j]); int ss=0; for(int i=1;i<=n;++i) if(canwin(N,i,n)) ans[ss++]=i; printf("%d",ans[0]); for(int i=1;i<ss;++i) printf(" %d",ans[i]); printf("\n"); } return 0; }