题意: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;
}