UVALive-2531 The K-League (最大流建模+枚举)
题目大意:有n支足球队,已知每支球队的已胜场数和任意两支球队之间还需要的比赛场数a[i][j],求最终可能夺冠的所有球队。
题目分析:枚举所有的球队,对于球队 i 让它在接下来的比赛中全部获胜,如果这样球队 i 还不能夺冠,那么 i 不是要找的,否则,就是答案。这道题可以建立公平分配问题的模型。将任意两个之间还有比赛的球队视作一个节点X(由u和v构成,即a[u][v]>0),则对于X有两个选择:u获胜或v获胜。这样的一个X相当于一个“任务”,对于每个任务X有两个“处理器”(u和v)供选择。建图如下:增加源点s和汇点t,由s出发向所有的X均连一条弧,容量为a[u][v],然后由X出发向其对应的u和v各连一条容量为无穷大的弧,最后对每个球队u都连一条指向汇点t的弧,容量为total-win(u),其中,total为 i 已经获胜的场数,win(u)为u已经获胜的场数。当源点出发的所有弧都饱和时,当前枚举的球队 i 则可能夺冠。
代码如下:
# include<iostream> # include<cstdio> # include<cmath> # include<string> # include<vector> # include<list> # include<set> # include<map> # include<queue> # include<cstring> # include<algorithm> using namespace std; # define LL long long # define REP(i,s,n) for(int i=s;i<n;++i) # define CL(a,b) memset(a,b,sizeof(a)) # define CLL(a,b,n) fill(a,a+n,b) const double inf=1e30; const int INF=1<<30; const int N=1000; struct Edge { int fr,to,cap,fw; Edge(int _fr,int _to,int _cap,int _fw):fr(_fr),to(_to),cap(_cap),fw(_fw){} }; vector<Edge>edges; vector<int>G[N]; int W[N],L[N],n,cur[N],vis[N],d[N]; int a[30][30],s,t,ans[30]; void addEdge(int u,int v,int cap) { edges.push_back(Edge(u,v,cap,0)); edges.push_back(Edge(v,u,0,0)); int m=edges.size(); G[u].push_back(m-2); G[v].push_back(m-1); } void read() { scanf("%d",&n); REP(i,0,n) scanf("%d%d",W+i,L+i); REP(i,0,n) REP(j,0,n) scanf("%d",&a[i][j]); } void init() { s=0,t=n*n+n+1; edges.clear(); REP(i,0,t+1) G[i].clear(); } bool BFS() { CL(vis,0); queue<int>q; vis[s]=1; d[s]=0; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); REP(i,0,G[u].size()){ Edge &e=edges[G[u][i]]; if(!vis[e.to]&&e.cap>e.fw){ vis[e.to]=1; d[e.to]=d[u]+1; q.push(e.to); } } } return vis[t]; } int DFS(int u,int a) { if(u==t||a==0) return a; int flow=0,f; for(int &i=cur[u];i<G[u].size();++i){ Edge &e=edges[G[u][i]]; if(d[e.to]==d[u]+1&&(f=DFS(e.to,min(a,e.cap-e.fw)))>0){ e.fw+=f; edges[G[u][i]^1].fw-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int Dinic() { int flow=0; while(BFS()){ CL(cur,0); flow+=DFS(s,INF); } return flow; } void solve() { ans[0]=0; REP(k,0,n){ int total=W[k]; REP(i,0,n) total+=a[k][i]; int flag=0; REP(i,0,n) if(W[i]>total){ flag=1; break; } if(flag) continue; init(); int full=0; REP(i,0,n){ REP(j,i+1,n){ full+=a[i][j]; if(a[i][j]>0) addEdge(s,i*n+j+1,a[i][j]); addEdge(i*n+j+1,n*n+i+1,INF); addEdge(i*n+j+1,n*n+j+1,INF); } if(W[i]<total) addEdge(n*n+i+1,t,total-W[i]); } int flow=Dinic(); if(flow==full) ans[++ans[0]]=k+1; } REP(i,1,ans[0]+1) printf("%d%c",ans[i],(i==ans[0])?'\n':' '); } int main() { int T; scanf("%d",&T); while(T--) { read(); solve(); } return 0; }