HDU 5294 Tricks Device(最短路+最大流)

Problem Description
Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the entrance of the tomb while Dumb Zhang’s at the end of it. The tomb is made up of many chambers, the total number is N. And there are M channels connecting the chambers. Innocent Wu wants to catch up Dumb Zhang to find out the answers of some questions, however, it’s Dumb Zhang’s intention to keep Innocent Wu in the dark, to do which he has to stop Innocent Wu from getting him. Only via the original shortest ways from the entrance to the end of the tomb costs the minimum time, and that’s the only chance Innocent Wu can catch Dumb Zhang.
Unfortunately, Dumb Zhang masters the art of becoming invisible(奇门遁甲) and tricks devices of this tomb, he can cut off the connections between chambers by using them. Dumb Zhang wanders how many channels at least he has to cut to stop Innocent Wu. And Innocent Wu wants to know after how many channels at most Dumb Zhang cut off Innocent Wu still has the chance to catch Dumb Zhang.
 

Input
There are multiple test cases. Please process till EOF.
For each case,the first line must includes two integers, N(<=2000), M(<=60000). N is the total number of the chambers, M is the total number of the channels.
In the following M lines, every line must includes three numbers, and use ai、bi、li as channel i connecting chamber ai and bi(1<=ai,bi<=n), it costs li(0<li<=100) minute to pass channel i.
The entrance of the tomb is at the chamber one, the end of tomb is at the chamber N.
 

Output
Output two numbers to stand for the answers of Dumb Zhang and Innocent Wu’s questions.
 

Sample Input
  
  
8 9 1 2 2 2 3 2 2 4 1 3 5 3 4 5 4 5 8 1 1 6 2 6 7 5 7 8 1
 

Sample Output
  
  
2 6
 

Author
FZUACM
 

Source
 
题意:
n个点,m条边,两个人,A在点1处,B在点n处,A必须走最短路到达n点(只走最短路,最短路可能多条)
B切断图中的某些边不让A到达n点
问:1.B最少切断多少边使A不能到达n点
       2.B最多切断多少边使A还能达到n点
分析:
问题1求最小割,根据最大流最小割定理,利用最大流求得,流量是1(边数)
对于问题2,只需在所有的最短路中找到边数最少的,然后用总边数m减去最少边的最短路上的边数
解释样例:












图中从1~8有3条最短路,长度都是8,都是最短路,B最少切断1-6,1-2让1-8不连通,最多切断除1-6-7-8外的其他所有边,此时1-8还有一条路
解法:
以给出的边权求最短路,根据最短路建图,判断边是否在最短路里面:d[v] - d[u] == w(u,v)
根据所建的新图,再求最短路(求最短路中的最少边数),每条边的权值变为1,
根据新图求最大流,流量为1(即最小割里的边权是1,是边数)
说明:代码很长不过都是模板,最大流的bfs、dfs模板都可以,最短路用的SPFA模板(很奇怪用Dijkstra怎么都过不了,不是超时而是WA。。。)
代码: dfs版增广路:
#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<stdlib.h>
#include<cctype>
#include<string>
using namespace std;
typedef long long ll;
const int N = 2000;
const int inf = 1 << 27;
const int M = 120000;
/****************************************最大流模板*********************************************/
struct Edge
{
    int to;//终点
    int cap;//容量
    int rev;//反向边
    Edge (int to = 0, int cap = 0, int rev = 0) : to (to), cap (cap), rev (rev) {}
};
struct EdmondsKarp
{
    bool used[M + 5];
    vector<Edge>v[M + 5];
    void AddEdge (int from, int to, int cap)
    {
        v[from].push_back (Edge (to, cap, v[to].size() ) );
        v[to].push_back (Edge (from, 0, v[from].size() - 1) );
    }
    int dfs (int s, int t, int f)
    {
        if (s == t) return f;
        used[s] = 1;
        for (int i = 0; i < v[s].size(); ++i)
        {
            Edge &tmp = v[s][i];//引用
            if (!used[tmp.to] && tmp.cap > 0)
            {
                int d = dfs (tmp.to, t, min (f, tmp.cap) );
                if (d > 0)
                {
                    tmp.cap -= d;
                    v[tmp.to][tmp.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }
    int MaxFlow (int s, int t) //求源点汇点的最大流
    {
        int flow = 0;
        while (1) //一直循环直到找不到增广路
        {
            mem (used, 0);
            int f = dfs (s, t, inf);
            if (f == 0) return flow;
            flow += f;
        }
    }
} q;
/***************************************最短路模板*****************************************/
struct Node
{
    int v, w;
    Node (int v = 0,int w = 0):v(v),w(w){}
};
struct Spfa
{
    int d[N+5];
    bool vis[N+5];
    queue<int>q;
    vector<Node>u[N+5];
    void init(int n)
    {
        while (!q.empty()) q.pop();
        for (int i = 0;i <= n;++i) u[i].clear();
        mem(vis,0);
    }
    void AddEdge(int uu,int vv,int ww)
    {
        u[uu].push_back(Node(vv,ww));
        u[vv].push_back(Node(uu,ww));
    }
    int spfa(int s, int t,int n)
    {
        for (int i = 0; i <= n; ++i) d[i] = inf;
        q.push (s);
        vis[s] = 1;
        d[s] = 0;
        while (!q.empty() )
        {
            int h = q.front();
            q.pop();
            vis[h] = 0;//spfa不同于bfs
            for (int i = 0; i < u[h].size(); ++i)
            {
                int &v = u[h][i].v, &w = u[h][i].w;
                if (d[v] > d[h] + w)
                {
                    d[v] = d[h] + w;
                    if (!vis[v])
                    {
                        q.push (v);
                        vis[v] = 1;
                    }
                }
            }
        }
        return d[t];
    }
} d,g;

/****************************************以最短路建图*********************************/
void make_map (int n)
{
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 0;j < d.u[i].size();++j)
        {
            int v = d.u[i][j].v, w = d.u[i][j].w;
            if (d.d[v] - d.d[i] == w)
            {
                q.AddEdge(i,v,1);//最大流,流量是1
                g.AddEdge(i,v,1);//最短路,边权是1
            }
        }
    }
}
/************************************************************************************/
int main()
{
    int n, m;
    while (~scanf ("%d %d", &n, &m) )
    {
        d.init (n);
        g.init (n);
        mem (q.v, 0);
        mem (q.used,0);
        for (int i = 0, u, v, w; i < m; ++i)
        {
            scanf ("%d %d %d", &u, &v, &w);
            d.AddEdge (u, v, w);
        }
        int minway = d.spfa (1, n, n);
        make_map (n);
        int ans1 = q.MaxFlow (1, n);
        int ans2 = m - g.spfa (1, n, n);
        printf ("%d %d\n", ans1, ans2);
    }
    return 0;
}
/*

7 12
1 2 1
2 7 8
1 7 8
1 6 7
6 7 1
2 3 3
3 6 3
6 4 1
7 4 2
1 5 2
5 4 4
7 5 6

*/
bfs版的增广路:
#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<stdlib.h>
#include<cctype>
#include<string>
using namespace std;
typedef long long ll;
const int N = 2000;
const int inf = 1<<27;
struct Node
{
    int v, w;
    Node (int v = 0,int w = 0):v(v),w(w){}
};
struct Spfa
{
    int d[N+5];
    bool vis[N+5];
    queue<int>q;
    vector<Node>u[N+5];
    void init(int n)
    {
        while (!q.empty()) q.pop();
        for (int i = 0;i <= n;++i) u[i].clear();
        mem(vis,0);
    }
    void AddEdge(int uu,int vv,int ww)
    {
        u[uu].push_back(Node(vv,ww));
        u[vv].push_back(Node(uu,ww));
    }
    int spfa(int s, int t,int n)
    {
        for (int i = 0; i <= n; ++i) d[i] = inf;
        q.push (s);
        vis[s] = 1;
        d[s] = 0;
        while (!q.empty() )
        {
            int h = q.front();
            q.pop();
            vis[h] = 0;//spfa不同于bfs
            for (int i = 0; i < u[h].size(); ++i)
            {
                int &v = u[h][i].v, &w = u[h][i].w;
                if (d[v] > d[h] + w)
                {
                    d[v] = d[h] + w;
                    if (!vis[v])
                    {
                        q.push (v);
                        vis[v] = 1;
                    }
                }
            }
        }
        return d[t];
    }
} d,g;
struct Edge
{
    int from, to, cap, flow;
    Edge (int u = 0, int v = 0, int c = 0, int f = 0) : from (u), to (v), cap (c), flow (f) {}
};
struct EdmondsKarp
{
    int n, m;
    vector<Edge>edges;//边数的两倍
    vector<int>G[N+5];//邻接表,G[i][j]表示节点i的第j条边在e数组中的序号
    int a[N+5];//当起点到i的可改进量
    int p[N+5];//最短路树上p的入弧编号
    void init (int n)
    {
        for (int i = 0; i <= n; ++i) G[i].clear();
        edges.clear();
    }
    void AddEdge (int from, int to, int cap)
    {
        edges.push_back (Edge (from, to, cap, 0) );
        edges.push_back (Edge (to, from, 0, 0) ); //反向弧
        m = edges.size();
        G[from].push_back (m - 2);
        G[to].push_back (m - 1);
    }
    int MaxFlow (int s, int t)
    {
        int flow = 0;
        while (1)
        {
            mem (a, 0);
            queue<int>Q;
            Q.push (s);
            a[s] = inf;
            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 (!a[e.to] && e.cap > e.flow)
                    {
                        p[e.to] = G[x][i];
                        a[e.to] = min (a[x], e.cap - e.flow);
                        Q.push (e.to);
                    }
                }
                if (a[t]) break;
            }
            if (!a[t]) break;
            for (int u = t; u != s; u = edges[p[u]].from)
            {
                edges[p[u]].flow += a[t];
                edges[p[u] ^ 1].flow -= a[t];
            }
            flow += a[t];
        }
        return flow;
    }
}q;
void make_map (int n)
{
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 0;j < d.u[i].size();++j)
        {
            int v = d.u[i][j].v, w = d.u[i][j].w;
            if (d.d[v] - d.d[i] == w)
            {
                q.AddEdge(i,v,1);//最大流,流量是1
                g.AddEdge(i,v,1);//最短路,边权是1
            }
        }
    }
}
int main()
{
    int n, m;
    while (~scanf ("%d %d", &n, &m) )
    {
        d.init (n);
        g.init (n);q.init(n);
        for (int i = 0, u, v, w; i < m; ++i)
        {
            scanf ("%d %d %d", &u, &v, &w);
            d.AddEdge (u, v, w);
        }
        int minway = d.spfa (1, n, n);
        make_map (n);
        int ans1 = q.MaxFlow (1, n);
        int ans2 = m - g.spfa (1, n, n);
        printf ("%d %d\n", ans1, ans2);
    }
    return 0;
}
/*

7 12
1 2 1
2 7 8
1 7 8
1 6 7
6 7 1
2 3 3
3 6 3
6 4 1
7 4 2
1 5 2
5 4 4
7 5 6
*/

关于增广路算法模板: 点击打开链接
据说HDU 3468也是最短路+最大流的题,找个时间干掉它~~~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值