您的位置:首页 > 其它

文章标题

2017-04-09 20:23 267 查看
题意:

给出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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  最小流问题