文章标题
2017-04-09 20:23
267 查看
题意:
给出N个点,M条路,求出从1到N 点的两条最短路的和最短,两条路径不能有重> 合的边。
思路:
按照一般的图论做题思路只能止步于最短路问题,但是这道题可以当作一道最
小费用流来写。从1到N走两次并且不能有重合的话,可以看作容量为2的网络
流问题,而路径的长度可以当作cost,这样就变成了最小流问题,这个做题方
式有两个很好的点:
1. 增广路
2. 记录前驱的路径
给出N个点,M条路,求出从1到N 点的两条最短路的和最短,两条路径不能有重> 合的边。
思路:
按照一般的图论做题思路只能止步于最短路问题,但是这道题可以当作一道最
小费用流来写。从1到N走两次并且不能有重合的话,可以看作容量为2的网络
流问题,而路径的长度可以当作cost,这样就变成了最小流问题,这个做题方
式有两个很好的点:
1. 增广路
2. 记录前驱的路径
#include <iostream> #include <cstring> #include <cstdio> #include <vector> using namespace std; const int MAXN = 10005; const int INF = 0x3f3f3f3f; struct edge { int to,cap,cost,rev; }; int V; vector<edge>G[MAXN]; int dist[MAXN]; int prevv[MAXN],preve[MAXN]; int N,M; int a[MAXN],b[MAXN],c[MAXN]; void add_edge(int from,int to,int cap,int cost) { G[from].push_back((edge){to,cap,cost,G[to].size()}); G[to].push_back((edge){from,0,-cost,G[from].size()-1}); } int min_costflow(int s,int t,int f) { int res = 0; while(f > 0) { memset(dist,INF,sizeof(dist)); dist[s] = 0; bool update = true; while(update) { update = false; for(int v = 0;v < V; v++) { if(dist[v] == INF) continue; for(int i = 0;i < G[v].size(); i++) { edge &e = G[v][i]; if(e.cap > 0 && dist[e.to] > dist[v] + e.cost) { dist[e.to] = dist[v] + e.cost; prevv[e.to] = v; preve[e.to] = i; update = true; } } } } if(dist[t] == INF) { return -1; } int d = f; for(int v = t;v != s; v = prevv[v]) { d = min(d,G[prevv[v]][preve[v]].cap); } f -= d; res += d*dist[t]; for(int v = t;v != s; v = prevv[v]) { edge &e = G[prevv[v]][preve[v]]; e.cap -= d; G[v][e.rev].cap += d; } } return res; } void solve() { int s = 0,t = N - 1; for(int i = 0;i < M; i++) { add_edge(a[i]-1,b[i]-1,1,c[i]); add_edge(b[i]-1,a[i]-1,1,c[i]); } printf("%d\n",min_costflow(s,t,2)); } int main() { //freopen("in.txt","r",stdin); scanf("%d%d",&N,&M); V = N; for(int i = 0;i < M; i++) { scanf("%d%d%d",&a[i],&b[i],&c[i]); } solve(); return 0; }