加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

HDU 4067 Random Maze 福州网预 费用流

(2011-10-08 13:49:53)
标签:

hdu

4067

random

maze

福州网预

费用流

it

分类: 网络流

题目描述:

200个点的图,告诉你一些单向边,每条边两个值ab,表示选与不选的花费。

现在让起点的出度-入度=1,终点的入度-出度=1,其他点的入度=出度。

问是否可能,可能的话最小花费是多少。

解题报告:

入度不足的用流补上,出度不足的流满即可。

一开始没仔细想,简单认为:

默认所有边选,删除一条边的代价为b – a,费用流求解,但是这样就可能有负环,果断TLE

 

随后,更改思路,具体算法如下:

Sum表示初始图的代价,开始时为0.

对于b>=a的边,那么默认这条边连接,边权为b-a(删除的费用),当前费用sum+=a,由于默认这条边连接,那么出度[from]++, 入度[to]++

对于b<a的边,那么默认这条边没有连接,加入tofrom的反向边,在流中就表示用这条反向边维护节点度的平衡,边权为a-b(添加的费用),当前费用sum+=b,由于默认不加这条边,所以出度入度就不用更新。

超级源点S,汇点T

出度>入度的,S连接之,容量为差值

入度>出度的,连接T,容量为差值

(注意图中起点和终点的+1-1的要求)

这样,如果满流,每个节点就满足了度的要求。

Sum+费用就是答案。

代码如下:

#include<iostream>

#include<cstring>

#include<cstdio>

#include<algorithm>

#include<map>

using namespace std;

 

 

#define size 200

#define Max 0x7fffffff

struct edge{int from, to, val, next, cost;} e[size * 40 + 20];

int v[size], cnt, pre[size], pos[size], dis[size], que[size * 10], vst[size];

void insert(int from, int to, int val, int cost)

{

    e[cnt].from = from, e[cnt].to = to, e[cnt].val = val;

    e[cnt].cost = cost, e[cnt].next = v[from];v[from] = cnt++;

    e[cnt].from = to, e[cnt].to = from;e[cnt].val = 0;

    e[cnt].cost = -cost, e[cnt].next = v[to];v[to] = cnt++;

}

bool spfa(int s, int t, int n)

{

    memset(pre, -1, sizeof(pre)); memset(vst, 0, sizeof(vst));

    int head, tail; head = tail = 0;

    for(int i = 1; i <= n; i++) dis[i] = Max;

    que[tail++] = s; pre[s] = s; dis[s] = 0; vst[s] = 1;

    while(head != tail)

    {

        int id = que[head++]; vst[id] = 0;

        id = v[id];

        while(id != -1)

        {

            if (e[id].val > 0 && dis[e[id].from] + e[id].cost < dis[e[id].to])

            {

                dis[e[id].to] = dis[e[id].from] + e[id].cost;

                pre[e[id].to] = e[id].from; pos[e[id].to] = id;

                if (!vst[e[id].to])

                {

                    vst[e[id].to] = 1;

                    que[tail++] = e[id].to;

                }

            }

            id = e[id].next;

        }

    }

    return pre[t] != -1 && dis[t] < Max;

}

int flow;

int MinCostFlow(int s, int t, int n)

{

    flow = 0; int cost = 0;

    while(spfa(s, t, n))

    {

        int fl = Max;

        for(int i = t; i != s; i = pre[i])

            if (e[pos[i]].val < fl) fl = e[pos[i]].val;

        flow += fl; cost += dis[t] * fl;

        for(int i = t; i != s; i = pre[i])

        {

            e[pos[i]].val -= fl;

            e[pos[i] ^ 1].val += fl;

        }

    }

    return cost; // flow是最大流值

}

int rd[200], cd[200];

int main()

{

    int tt, ca = 1; scanf("%d", &tt);while(tt--)

    {

        int n, m, a, b;

        scanf("%d%d%d%d", &n, &m, &a, &b);

        int s = 0, t = n + 1;

        memset(v, -1, sizeof(v)); cnt = 0; int sum = 0;

        memset(rd, 0, sizeof(rd));

        memset(cd, 0, sizeof(cd));

        for(int i = 0; i < m; i++)

        {

            int from, to, aa, bb;

            scanf("%d%d%d%d", &from ,&to, &aa, &bb);

            if (bb >= aa)

            {

                insert(from, to, 1, bb - aa);

                sum += aa;

                cd[from]++; rd[to]++;

            }else

            {

                insert(to, from, 1, aa - bb);

                sum += bb;

            }

        }

        int mm = 0, nn = 0;

        for(int i = 1; i <= n; i++)

        {

            int val = cd[i] - rd[i];

            if (i == a) val--;

            if (i == b) val++;

            if (val > 0) insert(s, i, val, 0), mm += val;

            else if (val < 0) insert(i, t, -val, 0), nn += -val;

        }

        int cost = MinCostFlow(s, t, t + 1);

        printf("Case %d: ", ca++);

        if (flow == mm && flow == nn) printf("%d\n", sum + cost);

        else printf("impossible\n");

    }

    return 0;

}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有