Farm Tour-最小費用最大流/SPFA

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條邊,還求大神解釋啊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章