LA 2531 The K-League

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


 

你可能感兴趣的:(ACM,图论,最大流)