POJ3921 && HDU 2485 Destroying the bus stations(最大流 or 费用流)

一道神奇的图论题,给出一个含n个点(n < 50), m条边 (m <= 4000),边权为1的有向图,求删除最少点数使得点1到点n不存在距离大于k的路径。 虽然有本书上有个用dfs递归求解的方法,但不太好理解。。。但是!用最大流和费用流都能解,网络流也忒强大了点,这就是传说中的“一切图论皆网络流”么。。。

我先用的费用流:建图:对每个点i拆点为i和i+n,令源点s=1,汇点t=2*n。增加弧(1, 1+n) ,(n, 2*n) 容量都为INF,费用都为0; 而对于非源汇点, 增加弧(i, i+n)容量为1, 费用为0。若原图中存在边(u, v),增加弧(u+n, v), 容量为1,费用为1(边权)。题目要求删点后点1到点n不存在距离大于k的路径,则对该网络求费用流,在费用大于k的时候停止(费用=边权=1).答案便是此时的最大流。

然后又用最大流做了一次:某本图论书上有这样一段话“在图中删除最少点使得源汇点失去连通性,一般用最小割最大流求解”.而对于这个题,显然在原图中本身从1到n的距离大于k的路径是不用考虑的,所以在建图前先要删去这些边。如何删去这些没用的边呢?用floyd!floyd求完所有点对距离后,对于边(u, v),若dist[1][u] + dist[v][n] + 1 <= k,则把这条边加到网络中去。。。建图与费用流基本相似,只是少了费用而已。

费用流代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;

const int maxn = 200;
const int INF = 1e9;
struct Edge
{
    int from, to, cap, flow, cost;
};
int n, m, k, s, t, flow, cost;
vector<Edge> edges;
vector<int> G[maxn];
int inq[maxn], d[maxn], a[maxn], p[maxn];

void init()
{
    for(int i=0; i<=t; i++) G[i].clear();
    edges.clear();
}

void add(int from, int to, int cap, int cost)
{
    edges.push_back((Edge){from, to, cap, 0, cost});
    edges.push_back((Edge){to, from, 0, 0, -cost});
    int tmp = edges.size();
    G[from].push_back(tmp-2);
    G[to].push_back(tmp-1);
}

bool bellmanford(int s, int t, int &flow, int &cost)
{
    for(int i=0; i<=t; i++) d[i] = INF;
    memset(inq, 0, sizeof(inq));
    d[s] = 0;   inq[s] = 1; p[s] = 0;   a[s] = INF;
    queue<int> Q; Q.push(s);
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop();
        inq[u] = 0;
        for(int i=0; i<G[u].size(); i++)
        {
            Edge& e = edges[G[u][i]];
            if(e.cap > e.flow && d[e.to] > d[u] + e.cost)
            {
                d[e.to] = d[u] + e.cost;
                p[e.to] = G[u][i];
                a[e.to] = min(a[u], e.cap - e.flow);
                if(!inq[e.to])
                {
                    Q.push(e.to);
                    inq[e.to] = 1;
                }
            }
        }
    }
    if(d[t] > k)    return false;//!!!
    flow += a[t];
    cost += d[t] * a[t];
    int u = t;
    while(u != s)
    {
        edges[p[u]].flow += a[t];
        edges[p[u]^1].flow -= a[t];
        u = edges[p[u]].from;
    }
    return true;
}

int MCMF()
{
    flow = 0, cost = 0;
    while(bellmanford(s, t, flow, cost));
    return flow;   //!!!
}

int main()
{
    while(scanf("%d%d%d", &n, &m, &k) && n+m+k)
    {
        s = 1; t =2*n;
        init();
        int u, v;
        while(m--)
        {
            scanf("%d%d", &u, &v);
            add(u+n, v, 1, 1);
        }
        for(int i=2; i<n; i++)  add(i, i+n, 1, 0);
        add(1, 1+n, INF, 0);
        add(n, 2*n, INF, 0);
        printf("%d\n", MCMF());
    }
}

然后是最大流代码:

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 200;
const int INF = 1e5;
struct Edge
{
    int from, to, cap, flow;
};
int n, m, k, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int d[maxn], cur[maxn];
int map[maxn][maxn], tmap[maxn][maxn];

inline void init()
{
    for(int i=0; i<=t; i++) G[i].clear();
    edges.clear();
}

void add(int from, int to, int cap)
{
    edges.push_back((Edge){from, to, cap, 0});
    edges.push_back((Edge){to, from, 0, 0});
    int tmp = edges.size();
    G[from].push_back(tmp-2);
    G[to].push_back(tmp-1);
}

bool bfs()
{
    memset(vis, 0, sizeof(vis));
    queue<int> q; q.push(s);
    d[s] = 0;   vis[s] = 1;
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        for(int i=0; i<G[x].size(); i++)
        {
            Edge& e = edges[G[x][i]];
            if(!vis[e.to] && e.cap > e.flow)
            {
                vis[e.to] = 1;
                d[e.to] = d[x] + 1;
                q.push(e.to);
            }
        }
    }
    return vis[t];
}

int dfs(int x, int a)
{
    if(x == t || a == 0)    return a;
    int flow = 0, f;
    for(int& i=cur[x]; i<G[x].size(); i++)
    {
        Edge& e = edges[G[x][i]];
        if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
        {
            e.flow += f;
            edges[G[x][i]^1].flow -=f;
            flow += f;
            a -= f;
            if(a == 0)  break;
        }
    }
    return flow;
}

int max_flow()
{
    int flow = 0;
    while(bfs())
    {
        memset(cur, 0, sizeof(cur));
        flow += dfs(s, INF);
    }
    return flow;
}

void floyd()
{
    memcpy(&tmap, &map, sizeof(map));
    for(int l=1; l<=n; l++)
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n;j++)
                if(tmap[i][j] > tmap[i][l] + tmap[l][j] && i != j)
                    tmap[i][j] = tmap[i][l] + tmap[l][j];
    for(int i=2; i<n; i++)     add(i, i+n, 1);
    add(1, 1+n, INF);
    add(n, 2*n, INF);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
        {
            if(map[i][j] == INF)    continue;
            if(tmap[1][i] + tmap[j][n] + 1 > k)     continue;
            add(i+n, j, INF);
        }
}

int main()
{
    while(scanf("%d%d%d", &n, &m, &k) && n+m+k)
    {
        s = 1;  t = 2*n;
        init();
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
                map[i][j] = INF;
            map[i][i] = 0;
        }
        int u, v;
        while(m--)
        {
            scanf("%d%d", &u, &v);
            map[u][v] = 1;
        }
        floyd();
        printf("%d\n", max_flow());
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值