HDU 5294--Tricks Device【最小割 && 最短路处理,新建图】

Tricks Device

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2208    Accepted Submission(s): 584


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
 

题意:

n个点,m条边,构建有权无向图。

求出删去最少条边数可以使得图没有最短路径,以及删出最多条边使得图仍有最多条路径。

思路:

(1)最短路处理出最短路径图,若dis[v] = dist[u] + w(u,v),则该路在最短路径中。把最短路的边加进最短路径图,边权值为1,在新图求最小割。转化成对立问题,求1 -> N的最大流。

(2)在跑最短路中用side数组记录最短路的最少边数,m - side[ n ]即为解。


最短路处理出最短路径图是本题的难点, 想了好久都没想明白,最后宇哥哥给讲了一下, 还是对spfa的理解不够深入。

最短路处理出最短路径图代码:

//重见图
void getmap(){
    for(int i = 1; i <= n; ++i)//枚举起点
    for(int j = head1[i]; j != -1 ; j = str[j].next){
        NODE E = str[j];
        if(dist[E.v] == dist[i] + E.w)//加上最短路上的边
            addedge(i, E.v, 1);
    }
}


AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define maxn 2000+100
#define maxm 200000+100
#define INF 0x3f3f3f3f
using namespace std;
int m, n;
int head[maxn], cur[maxn], cnt;
int head1[maxn], cnt1;
int dist[maxn], vis[maxn];
int side[maxn];
struct node{
    int u, v, cap, flow, next;
};
node edge[maxm];

struct NODE{
    int u, v, w, next;
};

NODE str[maxm];

void initedge(){
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void initstr(){
    cnt1 = 0;
    memset(head1, -1, sizeof(head1));
}

void addedge(int u, int v, int w){
    node E1 = {u, v, w, 0, head[u]};
    edge[cnt] = E1;
    head[u] = cnt++;
    node E2 = {v, u, 0, 0, head[v]};
    edge[cnt] = E2;
    head[v] = cnt++;
}

void addstr(int u, int v, int w){
    NODE E1 = {u, v, w, head1[u]};
    str[cnt1] = E1;
    head1[u] = cnt1++;
    NODE E2 = {v, u, w, head1[v]};
    str[cnt1] = E2;
    head1[v] = cnt1++;
}

void spfa(){//求出最短路径 + 到达N最少经过的边数,边数存在 side里面
    queue<int>q;
    for(int i = 1; i <= n; ++i){
        vis[i] = 0;
        dist[i] = INF;
        side[i] = 0;
    }
    vis[1] = 1;
    dist[1] = 0;
    q.push(1);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head1[u]; i != -1; i = str[i].next){
            int v = str[i].v;
            int w = str[i].w;
            if(dist[v] > dist[u] + w){
                dist[v] = dist[u] + w;
                side[v] = side[u] + 1;
                if(!vis[v]){
                    vis[v] = 1;
                    q.push(v);
                }
            }
            else if(dist[v] == dist[u] + w)
                side[v] = min(side[v], side[u] + 1);
        }
    }
}
//重见图
void getmap(){
    for(int i = 1; i <= n; ++i)//枚举起点
    for(int j = head1[i]; j != -1 ; j = str[j].next){
        NODE E = str[j];
        if(dist[E.v] == dist[i] + E.w)//加上最短路上的边
            addedge(i, E.v, 1);
    }
}

bool BFS(int st, int ed){
    queue<int>q;
    memset(vis, 0, sizeof(vis));
    memset(dist, -1, sizeof(dist));
    vis[st] = 1;
    dist[st] = 0;
    q.push(st);
    while(!q.empty()){
        int u =q.front();
        q.pop();
        for(int i = head[u]; i != -1; i = edge[i].next){
            node E = edge[i];
            if(!vis[E.v] && E.cap > E.flow){
                vis[E.v] = 1;
                dist[E.v] = dist[u] + 1;
                if(E.v == ed) return true;
                q.push(E.v);
            }
        }
    }
    return false;
}

int DFS(int x, int ed, int a){
    if(x == ed || a == 0)
        return a;
    int flow = 0, f;
    for(int &i = cur[x]; i != -1; i = edge[i].next){
        node &E = edge[i];
        if(dist[E.v] == dist[x] + 1 && (f = DFS(E.v, ed, min(a, E.cap - E.flow))) > 0){
            E.flow += f;
            edge[i ^ 1].flow -= f;
            a -= f;
            flow += f;
            if(a == 0) break;
        }
    }
    return flow;
}

int maxflow(int st, int ed){
    int flowsum = 0;
    while(BFS(st, ed)){
        memcpy(cur, head, sizeof(head));
        flowsum += DFS(st, ed, INF);
    }
    return flowsum;
}

int main (){
    while(scanf("%d%d", &n, &m) != EOF){
        initstr();
        for(int i = 1; i <= m; ++i){
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            addstr(u, v, w);
        }
        spfa();
        initedge();
        getmap();
        printf("%d %d\n", maxflow(1, n), m - side[n]);
    }
    return 0;
}




你可能感兴趣的:(HDU 5294--Tricks Device【最小割 && 最短路处理,新建图】)