[POJ 2391]Ombrophobic Bovines[最大流][二分答案]

来源:互联网 发布:unity3d 性能分析 编辑:程序博客网 时间:2024/05/09 03:05
题目链接:[POJ 2391]Ombrophobic Bovines[最大流][二分答案]

题意分析:

有F个地区,每个地区有have[i]头牛,可以提供can[i]头牛的庇护,有P条连接各个地区的无向道路,问:所有牛都能得到庇护,最少需要多少时间?

解题思路:

源点和牛间连一条容量为have[i]的边,汇点到牛间连一条容量为can[i]的边,需要将牛拆点(否则会发生串流,2->3 and 3->4 != 2->4)。用floyd预处理任意点间最短距离,二分答案,每次将距离小于等于答案的边添加进入图中,求最大流即可。如果满流就缩小答案,否则扩大答案。

个人感受:

第一想法是费用流,每次最大流的时候更新这条流的价值和到答案。然后写完WA了几发,自己给了自己一个反例:

3 3

2 2

0 2

2 0

1 2 10

3 1 10

3 2 100

ans: 10

然后floyd竟然写错了,太自信了= =。另外,网上一些过于优化的SAP也会WA,估计是优化过头出错误了。

具体代码如下:

#include<algorithm>#include<cctype>#include<cmath>#include<cstdio>#include<cstring>#include<iomanip>#include<iostream>#include<map>#include<queue>#include<set>#include<sstream>#include<stack>#include<string>#define lowbit(x) (x & (-x))#define ll long long#define pr(x) cout << #x << " = " << (x) << '\n';using namespace std;const int MAXN = 510;//点数的最大值const int MAXM = 540010;//边数的最大值const long long INF = 1e16;struct Edge{    int to,next,cap,flow;}edge[MAXM];//注意是MAXMint tol, src, des;int head[MAXN];int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];void init(){    tol = 0;    memset(head,-1,sizeof(head));}//加边,单向图三个参数,双向图四个参数void addedge(int u,int v,int w,int rw=0){    edge[tol].to = v;edge[tol].cap = w;edge[tol].next = head[u];    edge[tol].flow = 0;head[u] = tol++;    edge[tol].to = u;edge[tol].cap = rw;edge[tol].next = head[v];    edge[tol].flow = 0;head[v]=tol++;}//输入参数:起点、终点、点的总数//点的编号没有影响,只要输入点的总数int sap(int start,int end,int N){    memset(gap,0,sizeof(gap));    memset(dep,0,sizeof(dep));    memcpy(cur,head,sizeof(head));    int u = start;    pre[u] = -1;    gap[0] = N;    int ans = 0;    while(dep[start] < N)    {        if(u == end)        {            int Min = INF;            for(int i = pre[u];i != -1; i = pre[edge[i^1].to])            if(Min > edge[i].cap - edge[i].flow)                Min = edge[i].cap - edge[i].flow;            for(int i = pre[u];i != -1; i = pre[edge[i^1].to])            {                edge[i].flow += Min;                edge[i^1].flow -= Min;            }            u = start;            ans += Min;            continue;        }        bool flag = false;        int v;        for(int i = cur[u]; i != -1;i = edge[i].next)        {            v = edge[i].to;            if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u])            {                flag = true;                cur[u] = pre[v] = i;                break;            }        }        if(flag)        {            u = v;            continue;        }        int Min = N;        for(int i = head[u]; i != -1;i = edge[i].next)            if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)            {                Min = dep[edge[i].to];                cur[u] = i;            }        gap[dep[u]]--;        if(!gap[dep[u]])return ans;        dep[u] = Min+1;        gap[dep[u]]++;        if(u != start) u = edge[pre[u]^1].to;    }    return ans;}int have[MAXN], can[MAXN], f, sum;ll mp[MAXN][MAXN];void build(ll up) {    init();    for (int i = 1; i <= f; ++i) {        addedge(src, i, have[i]);        addedge(i + f, des, can[i]);        addedge(i, i + f, sum);        for (int j = i + 1; j <= f; ++j) {            if (mp[i][j] <= up) {                addedge(i, j + f, sum);                addedge(j, i + f, sum);            }        }    }}int main(){    int m;    while (~scanf("%d%d", &f, &m)) {        sum = 0;        for (int i = 1; i <= f; ++i) {            scanf("%d%d", &have[i], &can[i]);            sum += have[i];        }        int u, v, w;        for (int i = 1; i <= f; ++i)            for (int j = 1; j <= f; ++j)                mp[i][j] = INF;        for (int i = 0; i < m; ++i) {            scanf("%d%d%d", &u, &v, &w);            if (w < mp[u][v])                mp[u][v] = mp[v][u] = w;        }        src = 0, des = 2 * f + 1;        for (int i = 1; i <= f; ++i) {            for (int j = 1; j <= f; ++j) {                for (int k = 1; k <= f; ++k)                    mp[j][k] = min(mp[j][i] + mp[i][k], mp[j][k]);            }        }        ll ans = -1;        ll l = 1, r = INF - 1, mid;        while (l <= r) {            mid = (l + r) / 2;            build(mid);            if (sap(src, des, des + 1) >= sum) {                ans = mid;                r = mid - 1;            }            else l = mid + 1;        }        printf("%lld\n", ans);    }    return 0;}


0 0
原创粉丝点击