HDU 2485

    看来我还是不理解最小割的内涵...这题求的是最少去掉几个顶点,使得图的源点和汇点不连通。想想最小割的定义,如果图中每条边的流量都是1,那么最小割就变成了去掉最少的边,使得图的源点和汇点不连通。把这题中每个顶点拆分成两个顶点,中间用一条流量为1的边连接...这样,模型就满足最小割模型了。还有一个限制是路径长度大于k的路径可以不用考虑。这里只需按最小费用流建图,每条边的费用是1,当路径费用大于k的时候终止最大流过程即可。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <memory.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#include <iostream>
#include <sstream>

#define ll __int64

using namespace std;

typedef int typef;
typedef int typec;
#define inff 0x0fffffff
#define infc 0x0fffffff
#define N 100
#define E 10000

struct network
{
    int nv, ne, pnt[E], nxt[E];
    int vis[N], que[N], head[N], pv[N], pe[N];
    typef flow, cap[E]; typec cost, dis[E], d[N];
    void addedge(int u, int v, typef c, typec w) {
        pnt[ne] = v; cap[ne] = c;
        dis[ne] = w; nxt[ne] = head[u]; head[u] = ne++;
        pnt[ne] = u; cap[ne] = 0;
        dis[ne] = -w; nxt[ne] = head[v]; head[v] = ne++;
    }
    int mincost(int src, int sink, int limit) {
        int i, k, f, r; typef mxf;
        for(flow = 0, cost = 0; ; ) {
            memset(pv, -1, sizeof(pv));
            memset(vis, 0, sizeof(vis));
            for(i = 0; i < nv; ++i) d[i] = infc;
            d[src] = 0; pv[src] = src; vis[src] = 1;

            for(f = 0, r = 1, que[0] = src; r != f; ) {
                i = que[f++]; vis[i] = 0;
                if(N == f) f = 0;
                for(k = head[i]; k != -1; k = nxt[k])
                    if(cap[k] && dis[k]+d[i] < d[pnt[k]]) {
                        d[pnt[k]] = dis[k] + d[i];
                        if(0 == vis[pnt[k]]) {
                            vis[pnt[k]] = 1;
                            que[r++] = pnt[k];
                            if(N == r) r = 0;
                        }
                        pv[pnt[k]] = i; pe[pnt[k]] = k;
                    }
            }
            if(-1 == pv[sink]) break;
            if (d[sink] > limit) break;

            for(k = sink, mxf = inff; k != src; k = pv[k])
                if(cap[pe[k]] < mxf) mxf = cap[pe[k]];
            flow += mxf; cost += d[sink] * mxf;

            for(k = sink; k != src; k = pv[k]) {
                cap[pe[k]] -= mxf; cap[pe[k]^1] += mxf;
            }
        }
        return cost;
    }
    void init(int v) {
        nv = v; ne = 0;
        memset(head, -1, 4 * v);
    }
} D;

int main() {
    int n, m, k, x, y;
    while (scanf("%d %d %d", &n, &m, &k), n || m || k) {
        D.init(n * 2);
        for (int i = 0; i < n; i++)
            D.addedge(i * 2, i * 2 + 1, 1, 0);
        for (int i = 0; i < m; i++) {
            scanf("%d %d", &x, &y);
            x--, y--;
            D.addedge(x * 2 + 1, y * 2, 1, 1);
        }
        D.mincost(1, (n - 1) * 2, k);
        printf("%d\n", D.flow);
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值