HDU 4940 Destroy Transportation system(2014 Multi-University Training Contest 7)

思路:无源汇有上下界可行流判定, 原来每条边转化成  下界为D  上界为 D+B   ,判断是否存在可行流即可。

为什么呢?  如果存在可行流  那么说明对于任意的 S 集合流出的肯定等于 流入的, 流出的计算的 X 肯定小于等于这个流量(X是下界之和), 计算出来的Y (上界之和)肯定大于等于 这个流量  肯定满足X<=Y。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include <iostream>
#include<climits>
using namespace std;
const int N = 1000;
const int M = 100000;
int n;
int ecnt, head[N], nx[M], to[M], va[M], cur_edge[N];
int source, target, flow, pre[N], lev[N], qu[N], sign;
void addedge(int u, int v, int w) {
    to[ecnt] = v;
    nx[ecnt] = head[u];
    va[ecnt] = w;
    head[u] = ecnt++;
}
bool bfs(int s, int t) {
    std::fill(lev, lev + n, -1);
    sign = t;
    lev[t] = 0;
    int st = 0, ed = 0;
    qu[ed++] = t;
    while (st != ed && lev[s] == -1) {
        int u = qu[st++];
        for (int i = head[u]; i != -1; i = nx[i]) {
            if (va[i ^ 1] > 0 && lev[to[i]] == -1) {
                lev[to[i]] = lev[u] + 1;
                qu[ed++] = to[i];
            }
        }
    }
    return lev[s] != -1;
}
void push() {
    int delta = INT_MAX, u, p;
    for (u = target; u != source; u = to[p ^ 1]) {
        p = pre[u];
        delta = std::min(delta, va[p]);
    }
    for (u = target; u != source; u = to[p ^ 1]) {
        p = pre[u];
        va[p] -= delta;
        if (!va[p]) {//注意double时要改
            sign = to[p ^ 1];
        }
        va[p ^ 1] += delta;
    }
    flow += delta;
}
void dfs(int u) {
    if (u == target)
        push();
    else {
        for (int i = cur_edge[u]; i != -1; i = nx[i]) {
            if (va[i] > 0 && lev[u] == lev[to[i]] + 1) {
                pre[to[i]] = i;
                dfs(to[i]);
                if (lev[sign] > lev[u]) {
                    return;
                }
                sign = target;
            }
        }
        lev[u] = -1;
    }
}
int nc, pc, tc;
int lx[M], ly[M], lv[M];
void dinic(int s, int t, int node_cnt) {
    source = s;
    target = t;
    n = node_cnt;

    //construct graph

    flow = 0;
    while (bfs(source, target)) {
        for (int i = 0; i < n; ++i) {
            cur_edge[i] = head[i];
        }
        dfs(source);
    }

}
int in[500],out[500];
void solve() {
    int n,m;
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    scanf("%d%d",&n,&m);
    fill(head,head+n+10,-1);
    ecnt=0;
    for(int i=0;i<m;++i)
    {
        int u,v,x,y;
        scanf("%d%d%d%d",&u,&v,&x,&y);
        in[v]+=x;
        in[u]-=x;
        addedge(u,v,y);
        addedge(v,u,0);
    }
    int s,t;
    s=0;t=n+1;
    int sum=0;
    for(int i=1;i<=n;++i)
    {
        if(in[i]>0)
        {
            sum+=in[i];
            addedge(s,i,in[i]);
            addedge(i,s,0);
        }
        else
        {
            addedge(i,t,-in[i]);
            addedge(t,i,0);
        }
    }
    dinic(s,t,t+2);
    if(flow==sum)puts("happy");
    else puts("unhappy");
}
int main() {
    int ri=0,tt;
    scanf("%d",&tt);
    while(tt--)
    {
        printf("Case #%d: ",++ri);
        solve();
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/L-Ecry/p/3908004.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值