SGU 326. Perspective (最大流)

来源:互联网 发布:茶叶网络推广 编辑:程序博客网 时间:2024/04/30 13:10
LINK: http://acm.sgu.ru/problem.php?contest=0&problem=326
题意:两个赛区,每个赛区N个球队(标号1-N),现在已知一个赛区中每只球队赢得的场数和与每只球队还有多少场比赛(包括分区内和分区外),现在问你是否有可能让第一支球队成为分区第一。
    对于1-th, 无论是分区内还是分区外全让他赢,对于其他球队让分区外全输,分区内和1的比赛输,之后就是分配剩余的比赛(2~n球队之间的比赛)使得每个球队的胜场不超过w[1].
   这就可以用网络流解决了,设置源点S, 汇点T, 对于i,j之间发生的比赛, S向其连边大小为mat[i][j] ,它向i, j分别连边容量为INF, 对于球队i(i>1) 向汇点T连边容量为w[1] - w[i](注意判断容量正负)

   判断满流,如果满流表示可以分配。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<string>#include<vector>#include<cmath>#include<queue>#include<map>#include<set>using namespace std;#define INF 1000000000//typedef __int64 LL;#define N 500int t, n, m, k, tot, hh[N], lev[N], S, T;int w[N], r[N], mat[N][N];struct node{    int u, v, w, next;}edge[1000001];void init(){    tot = 0;    memset(hh, -1, sizeof(hh));}void add(int u, int v, int w){    edge[tot].u = u; edge[tot].v = v;    edge[tot].w = w; edge[tot].next = hh[u];    hh[u] = tot++;}int bfs(){    queue<int > Q;    memset(lev, -1, sizeof(lev));    Q.push(S); lev[S] = 0;    while(!Q.empty()) {        int u = Q.front(); Q.pop();        for(int i=hh[u]; i!=-1; i=edge[i].next) {            int v= edge[i].v, w = edge[i].w;            if(w && lev[v] == -1) {                lev[v] = lev[u] + 1;                Q.push(v);            }        }    }    return lev[T] != -1;}int dfs(int u, int flow){    if(u == T) return flow;    int tmp = flow, ad;    for(int i=hh[u]; i!=-1; i=edge[i].next) {        int v = edge[i].v;        if(lev[v] == lev[u] +1 && tmp >0 && edge[i].w) {            ad = dfs(v, min(tmp, edge[i].w));            if(!tmp) break;            edge[i].w -= ad;            edge[i^1].w += ad;            tmp -= ad;        }    }    if(ad == 0) lev[u] = -1;    return flow - tmp;}int dinic(){    int ret = 0, tmp;    while(bfs()) {        while( tmp = dfs(S, INF)) ret += tmp;    }    return ret;}int main(){#ifndef ONLINE_JUDGEfreopen("in.txt", "r", stdin);#endif // ONLINE_JUDGEwhile(scanf("%d", &n) != EOF) {        for(int i=1; i<=n; i++) scanf("%d", &w[i]);        for(int i=1; i<=n; i++) scanf("%d", &r[i]);        for(int i=1; i<=n; i++) {            for(int j=1; j<=n ;j++) {                scanf("%d", &mat[i][j]);            }        }        w[1] += r[1];        init();        S = 0;        int cc = n;        int sum = 0;        for(int i=2; i<=n; i++) {            for(int j=i+1; j<=n; j++) {                if(mat[i][j] == 0) continue;                cc ++;                sum += mat[i][j];                add(S, cc, mat[i][j]); add(cc, S, 0);                add(cc, i, INF); add(i, cc, 0);                add(cc, j, INF); add(j, cc, 0);            }        }        T = cc+1;        int flag = 0;        for(int i=2; i<=n; i++) {            if(w[1] < w[i]) {                flag = 1; break;            }            add(i, T, w[1] - w[i]); add(T, i, 0);        }        if(flag) {            printf("NO\n"); continue;        }        int ans = dinic();        if(ans >= sum) printf("YES\n");        else printf("NO\n");}return 0;}


0 0