Farm Tour
問題來源:poj-2135
Description
When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of which contains his house and the Nth of which contains the big barn. A total M (1 <= M <= 10000) paths that connect the fields in various ways. Each path connects two different fields and has a nonzero length smaller than 35,000.
To show off his farm in the best way, he walks a tour that starts at his house, potentially travels through some fields, and ends at the barn. Later, he returns (potentially through some fields) back to his house again.
He wants his tour to be as short as possible, however he doesn't want to walk on any given path more than once. Calculate the shortest tour possible. FJ is sure that some tour exists for any given farm.
Input
* Line 1: Two space-separated integers: N and M.
* Lines 2..M+1: Three space-separated integers that define a path: The starting field, the end field, and the path's length.
Output
A single line containing the length of the shortest tour.
Sample Input
4 5
1 2 1
2 3 1
3 4 1
1 3 2
2 4 2
Sample Output
6
源代碼:
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
struct Edge{
int from , to , cost , cap , next;
};
queue <int> Q;
const int MAXN = 1002;
const int MAX = 40008;
const int INF = 1<<29;
int N , M , S , T , num;
int head[MAXN] , pre[MAXN] , dis[MAXN];
bool mark[MAXN];
Edge edge[MAX];
//head是鄰接表的首節點所在edge的索引
//pre是點在鄰接表的索引
//dis是SPFA算法的距離(離源點)
bool SPFA( void );
int update( void );
int minCost( void );
void add_edge( int a , int b , int c , int f );
int main( ){
int i , a , b , c;
while( cin>>N>>M ){
num = 0;
S = 0;
T = N + 1;
memset( head , -1 , sizeof( head ) );
for( i=1 ; i<=M ; i++ ){
cin>>a>>b>>c;
add_edge( a , b , c , 1 );
add_edge( b , a , c , 1 );
}
add_edge( S , 1 , 0 , 2 );
add_edge( N , T , 0 , 2 );
cout<<minCost()<<endl;
}
return 0;
}
void add_edge( int a , int b , int c , int f ){
edge[num].from = a; //正向邊
edge[num].to = b;
edge[num].cost = c; //費用爲正
edge[num].cap = f; //容量爲正
edge[num].next = head[a];
head[a] = num++;
edge[num].from = b; //負向邊
edge[num].to = a;
edge[num].cost = -c; //費用爲負
edge[num].cap = 0; //容量爲0
edge[num].next = head[b];
head[b] = num++;
}
int minCost( void ){
int sum = 0;
while( SPFA( ) ){
sum += update( );
}
return sum;
}
bool SPFA( void ){
int i , j , u , v;
memset( mark , false , sizeof( false ) );
memset( pre , -1 , sizeof( pre) );
for( i=S ; i<=T ; i++ ) dis[i] = INF;
while( !Q.empty( ) ) Q.pop( );
dis[S] = 0;
Q.push( S );
mark[S] = true;
while( !Q.empty( ) ){
u = Q.front( );
Q.pop( );
//與BFS不同點一:新節點要做鬆弛操作
mark[u] = false;
//與BFS不同點二:SPFA算法沒有終止條件
for( j=head[u] ; j!=-1 ; j=edge[j].next ){
v = edge[j].to;
if( edge[j].cap && dis[u]+edge[j].cost<dis[v] ){
dis[v] = dis[u] + edge[j].cost;
pre[v] = j;
if( !mark[v] ){
Q.push( v );
mark[v] = true;
}
}
}
}
if( pre[T]==-1 )
return false;
return true;
}
int update( void ){
int k , u , v;
k = pre[T];
while( k!=-1 ){
edge[k].cap--; //容量減少1
edge[k^1].cap++; //反向容量增1
k = pre[edge[k].from]; //尋找上一個節點在edge中的位置
}
return dis[T];
}
代碼分析:最小費用最大流的一個模板,數據結構使用了靜態數組來實現鄰接表,同時用了SFPA算法求最短路,我覺得加邊的那部分是精華,看帖寫的,也不是太明白爲什麼要加成4條邊,還求大神解釋啊