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; }