题意:在一张N * M 的图中,有 n个房子和n个人。问最少使用多少总步数让每个房子都有且仅有一个人.
解析:构图。选取源点和汇点,从源点到人连通,费用为0(因为题目要求的是人到房子的费用)。以第i个人与第j所房子的距离作为当前费用进行构图,由于题目并不需要求出最大流( 也没给出来),因此所有连通路径的流量设置为一个相同的权值即可。
然后使用费用流求出最小费用。
#include<iostream> #include<cstdio> #include<queue> #include<cmath> #include<cstring> using namespace std; //最小费用最大流,求最大费用只需要取相反数,即结果取反即可;点数为N,编号从0~N - 1 const int maxn = 10000; const int maxm = 100000; const int INF = 0xfffffff; struct Edge{ int to, next, cap, flow, cost; }edge[ maxm ]; int head[ maxn ], tol; int pre[ maxn ], dis[ maxn ]; bool vis[ maxn ]; int N;//节点个数,编号从0~N-1 void init( int n ){ N = n; tol = 0; memset( head, -1, sizeof( head ) ); } void addedge( int u, int v, int cap, int cost ){ edge[ tol ].to = v; edge[ tol ].cap = cap; edge[ tol ].cost = cost; edge[ tol ].flow = 0; edge[ tol ].next = head[ u ]; head[ u ] = tol++; edge[ tol ].to = u; edge[ tol ].cap = 0; edge[ tol ].cost = -cost; edge[ tol ].flow = 0; edge[ tol ].next = head[ v ]; head[ v ] = tol++; } bool spfa( int s, int t ){ queue< int > q; for( int i = 0; i < N; ++i ){ dis[ i ] = INF; vis[ i ] = false; pre[ i ] = -1; } dis[ s ] = 0; vis[ s ] = true; q.push( s ); while( !q.empty( ) ){ int u = q.front(); q.pop(); vis[ u ] = false; for( int i = head[ u ]; i != - 1; i = edge[ i ].next ){ int v = edge[ i ].to; if( edge[ i ].cap > edge[ i ].flow && dis[ v ] > dis[ u ] + edge[ i ].cost ){ dis[ v ] = dis[ u ] + edge[ i ].cost; pre[ v ] = i; if( !vis[ v ] ){ vis[ v ] = true; q.push( v ); } } } } if( pre[ t ] == -1 ) return false; else return true; } //返回值:flow为最大流;cost为最小费用 int minCostMaxflow( int s, int t, int &cost ){ int flow = 0; cost = 0; while( spfa( s, t ) ){ int Min = INF; for( int i = pre[ t ]; i != - 1; i = pre[ edge[ i ^ 1 ].to ] ){ if( Min > edge[ i ].cap - edge[ i ].flow ) Min = edge[ i ].cap - edge[ i ].flow; } for( int i = pre[ t ]; i != -1; i = pre[ edge[ i ^ 1 ].to ] ){ edge[ i ].flow += Min; edge[ i ^ 1 ].flow -= Min; cost += edge[ i ].cost * Min; } flow += Min; } return cost; } struct node{ int x, y; }Home[ 205 ], Man[ 205 ]; char mapp[ 205 ][ 205 ]; int main(){ int n, m; while( scanf( "%d%d", &n, &m ) != EOF ){ if( !n && !m ) break; int k1 = 0, k2 = 0; for( int i = 0; i < n; ++i ){ scanf( "%s", &mapp[ i ] ); for( int j = 0; j < m; ++j ){ //k1++; if( mapp[ i ][ j ] == 'H' ){ k1++; Home[ k1 ].x = i; Home[ k1 ].y = j; } else if( mapp[ i ][ j ] == 'm' ){ k2++; Man[ k2 ].x = i; Man[ k2 ].y = j; } } } //cout << k1 << " " << k2 << endl; int start = 0, end = k1 + k2 + 1, N = k1 + k2 + 2; init( N ); for( int i = 1; i <= k1; ++i ){ addedge( 0, i, 1, 0 ); } for( int i = 1; i <= k2; ++i ){ addedge( k1 + i, end, 1, 0 ); } for( int i = 1; i <= k1; ++i ){ for( int j = 1; j <= k2; ++j ){ int temp = abs( Home[ i ].x - Man[ j ].x ) + abs( Home[ i ].y - Man[ j ].y ); //cout << temp << endl; addedge( i, k1 + j, 1, temp ); } } int c; int ans = minCostMaxflow( start, end, c ); cout << ans << endl; } return 0; } /* 2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 2 10 28 */
原文:http://blog.csdn.net/bo_jwolf/article/details/38014417