标签:
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
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【最小割 && 最短路处理,新建图】
标签:
原文地址:http://blog.csdn.net/hpuhjh/article/details/47345361