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;
}

  

posted @ 2015-12-08 21:46  20143605  阅读(336)  评论(0编辑  收藏  举报