1506: Double Shortest Paths
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 338 Solved: 122
[ Submit][ Status][ Web Board]
Description
Input
There will be at most 200 test cases. Each case begins with two integers n, m (1<=n<=500, 1<=m<=2000), the number of caves and passages. Each of the following m lines contains four integers u, v, di and ai (1<=u,v<=n, 1<=di<=1000, 0<=ai<=1000). Note that there can be multiple passages connecting the same pair of caves, and even passages connecting a cave and itself.
Output
For each test case, print the case number and the minimal total difficulty.
Sample Input
4 4
1 2 5 1
2 4 6 0
1 3 4 0
3 4 9 1
4 4
1 2 5 10
2 4 6 10
1 3 4 10
3 4 9 10
Sample Output
Case 1: 23Case 2: 24
解题思路:这里的边可能有两次费用,第一次走是di,第二次走是di+ai,所以这里干脆就两节点之间建立两条边,容量都为1,费用分别为di和di+ai,然后再用超级源点与1号节点连接,容量为2(走两次),费用为0,同理,超级汇点与n号节点连接,容量为2。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn = 505; const int inf = 0x3f3f3f3f; struct Edge { int from,to,next,flow,cost; }edge[10000]; int n,m,cnt,head[maxn],pre[maxn]; int dis[maxn],st,ed; bool inq[maxn]; void addedge(int u,int v,int flow,int cost) { edge[cnt].from = u; edge[cnt].to = v; edge[cnt].flow = flow; edge[cnt].cost = cost; edge[cnt].next = head[u]; head[u] = cnt++; swap(u,v); edge[cnt].from = u; edge[cnt].to = v; edge[cnt].flow = 0; edge[cnt].cost = -cost; edge[cnt].next = head[u]; head[u] = cnt++; } int spfa(int s,int t) { queue<int> q; memset(dis,inf,sizeof(dis)); memset(inq,false,sizeof(inq)); memset(pre,-1,sizeof(pre)); //pre[i]表示最短路径上以i为终点的边的编号 dis[s] = 0; inq[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); inq[u] = false; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(dis[v] > dis[u] + edge[i].cost && edge[i].flow > 0) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if(inq[v] == false) { inq[v] = true; q.push(v); } } } } return dis[t] != inf; } int MCMF(int s,int t) { int mincost = 0,minflow,sumflow = 0; //最小费用,路径中最小流量,总流量 while(spfa(s,t)) //找当前的最短路 { minflow = inf; for(int i = pre[t]; i != -1; i = pre[edge[i].from]) minflow = min(minflow,edge[i].flow); sumflow += minflow; for(int i = pre[t]; i != -1; i = pre[edge[i].from]) { edge[i].flow -= minflow; edge[i^1].flow += minflow; } mincost += dis[t] * minflow; } return mincost; } int main() { int u,v,d,a,cas = 1; while(scanf("%d %d",&n,&m)!=EOF) { st = 0, ed = n + 1; cnt = 0; memset(head,-1,sizeof(head)); for(int i = 1; i <= m; i++) { scanf("%d %d %d %d",&u,&v,&d,&a); addedge(u,v,1,d); addedge(u,v,1,d+a); } addedge(st,1,2,0); addedge(n,ed,2,0); printf("Case %d: %d\n",cas++,MCMF(st,ed)); } return 0; }