题目大意:给出v个点和e条边的有向带权图,求1~v俩条不相交的路径,使权和最小
解题思路:因为要求不相交,所以可以将2~v-1拆成俩个点i,ii,中间连一条容量1费用0的边,然后按照带权图的边将入度全连在i上,出度全连ii上,容量全部为1,费用为权值,将s与1连接,费用0,容量2,v与t连接,费用0,容量2,求最小费用流即可获得答案
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <vector>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 10000
struct Edge {
int from, to, cost, cap, flow;
Edge(int from, int to, int cost, int cap, int flow):from(from), to(to), cost(cost), cap(cap), flow(flow){}
};
int m;
vector<int> G[maxn];
vector<Edge> edges;
void addEdge(int x, int y, int co, int c) {
if(x != 0 && x != 1 && y < m+1) {
x += m+1;
}
edges.push_back(Edge(x, y, co, c, 0));
edges.push_back(Edge(y, x, -co, 0, 0));
int i = edges.size();
G[x].push_back(i-2);
G[y].push_back(i-1);
}
void init(int k) {
edges.clear();
for(int i = 0; i <= 2*m+1; i++)
G[i].clear();
while(k--) {
int x, y, cost;
cin >> x >> y >> cost;
addEdge(x, y, cost, 1);
}
addEdge(0, 1, 0, 2);
addEdge(m, m+1, 0, 2);
for(int i = 1; i <= m-1; i++) {
addEdge(i, i+m+1, 0, 1);
}
}
long long int BF(int s, int t) {
long long int re = 0;
int flow;
int flo[maxn];
int cos[maxn];
int pre[maxn];
while(1) {
queue<int> que;
int inq[maxn];
for(int i = 0; i <= 2*m+2; i++) {
cos[i] = INF;
}
cos[s] = 0;
memset(flo, 0, sizeof(flo));
memset(inq, 0, sizeof(inq));
flo[s] = INF;
pre[s] = 0;
que.push(s);
inq[s] = 1;
while(!que.empty()) {
int po = que.front();
que.pop();
inq[po] = 0;
for(int i = 0; i < G[po].size(); i++) {
Edge& ed = edges[G[po][i]];
if(cos[ed.to] > cos[po] + ed.cost && ed.cap > ed.flow) {
cos[ed.to] = cos[po] + ed.cost;
pre[ed.to] = G[po][i];
flo[ed.to] = min(ed.cap - ed.flow, flo[po]);
if(!inq[ed.to]) {
que.push(ed.to);
inq[ed.to] = 1;
}
}
}
}
if(cos[t] == INF) {
return re;
}
flow += flo[t];
re += (long long int)flo[t] * (long long int)cos[t];
for(int i = t; i != s; i = edges[pre[i]].from) {
edges[pre[i]].flow += flo[t];
edges[pre[i]^1].flow -= flo[t];
}
}
}
int main() {
int k;
while(cin >> m >> k && m) {
init(k);
cout << BF(0, m+1) << endl;
}
return 0;
}