Memory Limit: 65536kb
Given a bidirectional graph G=(V,E) with n vertices and m edges, it’s easy to find the shortest path between vertex S and T. Your task is to delete a set of edges with minimum cost, such that the shortest path in new graph is longer than the original one.
The first line of each test case contains two integers n and m, which specify the number of vertices and edges. (2 ≤ n ≤ 1000, 1 ≤ m ≤ 10000). The second line consists of two integer S and T, indicating the source and the sink. (1 ≤ S,T ≤ n, S ≠ T) The next m lines each contains four integers ui, vi, wi and ci, indicating that there’s an edge between vertex ui and vi with length wi, and the cost of deleting it is ci. (1 ≤ ui,vi ≤ n, 0 ≤wi,ci ≤ 1000)
A test case with n=m=0 indicates the end of input.
It is guaranteed that shortest path in initial graph always exists, and length of the shortest path between S and T is regarded as infinity if they are not connected.
2 3 1 2 1 2 2 3 1 2 2 4 1 2 3 5 4 5 1 4 1 2 1 1 2 3 1 1 3 4 1 1 1 4 3 2 2 2 2 3 4 5 2 3 1 2 3 2 2 4 3 4 1 3 2 3 3 4 2 3 1 4 0 1 0 0
Case 1: 7 Case 2: 3 Case 3: 6
题意:给出一个无向图,给出起点s和终点t,s到t之间存在最短路径,每条边都有各自的花费,若删除某条边,则要付出对应的花费。现在要删除一些边,使得s到t之间的最短路径变长(s与t不连通时最短路径为INF),问最小的花费是多少。
思路:要删除的边一定在s到t的最短路径上,先spfa求一次最短路,然后枚举每条边,若dis[u] + w == dis[v],那么这条边在最短路径上,把这条边加入到网络流中,最后求最小割即可。
AC代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> #define L(rt) (rt<<1) #define R(rt) (rt<<1|1) using namespace std; const int maxn = 20005; const int maxm = 500005; const int INF = 1000000000; struct edge{ int u, v, w, cost, next; }et1[maxn]; struct Edge{ int u, v, cap, flow, next; }et2[maxm]; int eh1[maxn], eh2[maxn], low[maxn], dis1[maxn], dis2[maxn], cnt[maxn], pre[maxn], cur[maxn]; bool vis[maxn]; int n, m, s, t, num1, num2; void init(){ memset(eh1, -1, sizeof(eh1)); memset(eh2, -1, sizeof(eh2)); num1 = num2 = 0; } void add1(int u, int v, int w, int cost){ edge e = {u, v, w, cost, eh1[u]}; et1[num1] = e; eh1[u] = num1++; } void add2(int u, int v, int cap, int flow){ Edge e = {u, v, cap, flow, eh2[u]}; et2[num2] = e; eh2[u] = num2++; } void addedge(int u, int v, int cap){ add2(u, v, cap, 0); add2(v, u, 0, 0); } void spfa(){ queue<int> Q; memset(vis, false, sizeof(vis)); for(int i = 1; i <= n; i++) dis1[i] = INF; dis1[s] = 0; vis[s] = true; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = false; for(int i = eh1[u]; i != -1; i = et1[i].next) { int v = et1[i].v, w = et1[i].w; if(dis1[u] + w < dis1[v]) { dis1[v] = dis1[u] + w; if(!vis[v]) { vis[v] = true; Q.push(v); } } } } } void build(){ for(int i = 0; i < num1; i++) { int u = et1[i].u, v = et1[i].v, w = et1[i].w, cost = et1[i].cost; if(dis1[u] + w == dis1[v]) addedge(u, v, cost); } } int isap(int s, int t, int nv){ int u, v, now, flow = 0; memset(low, 0, sizeof(low)); memset(cnt, 0, sizeof(cnt)); memset(dis2, 0, sizeof(dis2)); for(u = 0; u <= nv; u++) cur[u] = eh2[u]; low[s] = INF, cnt[0] = nv, u = s; while(dis2[s] < nv) { for(now = cur[u]; now != -1; now = et2[now].next) if(et2[now].cap - et2[now].flow && dis2[u] == dis2[v = et2[now].v] + 1) break; if(now != -1) { cur[u] = pre[v] = now; low[v] = min(low[u], et2[now].cap - et2[now].flow); u = v; if(u == t) { for(; u != s; u = et2[pre[u]].u) { et2[pre[u]].flow += low[t]; et2[pre[u]^1].flow -= low[t]; } flow += low[t]; low[s] = INF; } } else { if(--cnt[dis2[u]] == 0) break; dis2[u] = nv, cur[u] = eh2[u]; for(now = eh2[u]; now != -1; now = et2[now].next) if(et2[now].cap - et2[now].flow && dis2[u] > dis2[et2[now].v] + 1) dis2[u] = dis2[et2[now].v] + 1; cnt[dis2[u]]++; if(u != s) u = et2[pre[u]].u; } } return flow; } int main() { int u, v, w, c, ca = 0; while(scanf("%d%d", &n, &m), n || m) { init(); scanf("%d%d", &s, &t); while(m--) { scanf("%d%d%d%d", &u, &v, &w, &c); add1(u, v, w, c); add1(v, u, w, c); } spfa(); build(); printf("Case %d: %d\n", ++ca, isap(s, t, n + 1)); } return 0; }