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

  

时间: 2024-07-30 20:21:07

UVALive-2531 The K-League (最大流建模+枚举)的相关文章

UVALive - 2531 The K-League(最大流+枚举)

题目大意:有n支队伍进行比赛,每支队伍需要打的比赛次数相同,每场比赛恰好有一支队伍胜,一支队伍败,给出每支队伍目前胜的场数和败的场数,以及每两支队伍还剩下的比赛场数,确定所有可能得冠军的队伍 解题思路:枚举每支队伍,然后让该队伍在接下来的所有比赛中都获胜. 建图的话,就比较简单了,源点连向每场比赛,容量为比赛次数 每场比赛连向比赛队伍,容量为比赛次数 接着每支队伍连向汇点,容量为枚举队伍的总胜场-该队伍的胜场 如果满流,表示该队伍可以得到冠军 #include <cstdio> #includ

【Uvalive 2531】 The K-League (最大流-类似公平分配问题)

[题意] 有n个队伍进行比赛,每场比赛,恰好有一支队伍取胜.一支队伍败.每个队伍需要打的比赛场数相同,给你每个队伍目前已经赢得场数和输得场数,再给你一个矩阵,第 i 行第 j 列 表示队伍 i 和队伍 j 还需要打的比赛数,问你哪些队伍有可能获得冠军(胜场最多的即为冠军,可以并列). InputThe input consists of T test cases. The number of test cases (T) is given in the first line of the inp

UVALive - 2957 Bring Them There(最大流 图论建模)

题目大意:有n个星球,你的任务是用最短的时间把k个超级计算机从S星球运送到T星球.每个超级计算机需要一艘飞船来运输,行星之间有m条双向隧道,每条隧道需要一天时间来通过,且不能有两艘飞船同时使用同一条隧道,隧道不会连接两个相同的行星,且每一对行星之间最多只有一条隧道 解题思路:按照大白书上的思路是拆点 比如运送的时间为T,那么就把每个点u拆成T + 1个,分别为u0, u1 - uT,分别对应的是第i天的u星球 对于所给的每条边(u,v),假设是第i天,就连边ui –>vi+1和vi–>ui+1

poj3281 dining 经典最大流建模方法

题意:有f中食物和D种饮料,每头牛只能享用一种食物和饮料,每个食物跟饮料也只能被一头牛享用.现在有n头牛,每头牛都有自己喜欢的食物种类列表和饮料列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料.f,d,n都是一百以内的. 思路:就不说一开始的想法了,是最近学习的最大流的建模里面的新的方法. 之前做过几道题,比如poj2391这道,它是比较一般的左边一些点代表着供应,2391这道题就是每个点的牛的数量,右边一个点集代表了需求并与汇点连接,这道题就是每个点能容纳的牛数,然后拆点联一下套模板就好了

UVALive - 2197 Paint the Roads(费用流)

题目大意:有n个点,m条边,你的任务是选择其中的一些边,使得每条被选择的边组成一些没有公共边的回路,且每个城市恰好在其中的k个回路上,被选择的边的总权值要求最小 解题思路:k个回路,每个城市都有,表示每个城市的入度和出度都是k,所以以此建边 源点连向每个城市,容量为k,费用0 每个城市连向汇点,容量为k,费用0 边连接两个城市,容量为1,费用为权值 跑最小费用最大流 #include <cstdio> #include <cstring> #include <algorith

【 UVALive - 5095】Transportation(费用流)

Description There are N cities, and M directed roads connecting them. Now you want to transport K units ofgoods from city 1 to city N. There are many robbers on the road, so you must be very careful. Themore goods you carry, the more dangerous it is.

UVA11082 Matrix Decompressing 最大流建模解矩阵,经典

/** 题目:UVA11082 Matrix Decompressing 链接:https://vjudge.net/problem/UVA-11082 题意:lrj入门经典P374 已知一个矩阵的行数为r,列数为c,前i行的和ai(1<=i<=r),前j列的和bj(1<=j<=c). ai,bj都在[1,20]内.求出这个矩阵. 思路:通过前i行的和以及前j列的和,获得每一行的和以及每一列的和. 把每一行看做一个节点,每一列看做一个节点. 建立一个源点到达每一行. 建立一个汇点,

POJ1149 PIGS 最大流-建模

题目链接: POJ1149 题意: 麦克是农场主有N个猪圈,每个猪圈都有一把锁但麦克没有钥匙.要买猪的顾客一个接一个来到养猪场,每个顾客有一些猪圈的钥匙,而且他们要买一定数量的猪.当每个顾客到来时,他将那些他拥有钥匙的猪圈全部打开:迈克从这些猪圈中挑出一些猪卖给他们:如果迈克愿意,迈克可以重新分配这些被打开的猪圈中的猪:当顾客离开时,猪圈再次被锁上.给出每个猪圈的初始的猪的数量,求麦克能卖出猪的最大数量 思路: 注意顾客是一个接一个有顺序来的 网络流以顾客为节点建模 1) 将顾客看作除源点和汇点

POJ 3189--Steady Cow Assignment【二分图多重匹配 &amp;&amp; 最大流求解 &amp;&amp; 枚举 &amp;&amp; 经典】

Steady Cow Assignment Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6023   Accepted: 2078 Description Farmer John's N (1 <= N <= 1000) cows each reside in one of B (1 <= B <= 20) barns which, of course, have limited capacity. So