题目:在一个N * M 的矩阵草原上,分布着羊和狼,每个格子只能存在0或1只动物。现在要用栅栏将所有的狼和羊分开,问怎么放,栅栏数放的最少,求出个数?
解析:将狼群看作一个集合,羊群看作一个集合。然后设置源点和汇点,将两点至存在动物的点的距离赋值为1,构图,由于求得是栅栏数,从存在动物的位置向四周发散点赋值为1,即该方向放置一个栅栏。然后可以发现变成了求最小割,即求出最大流。需要注意的是,由于数据比较大,200 * 200。如果设置源点和汇点相差较大(即s = 0,e = n * m ),容易TLE.
#include<iostream> #include<cstdio> #include<cstring> using namespace std; // 最大流 ISAP + bfs+栈优化 const int maxn = 100010; //点的个数 const int maxm = 400010; //边的个数 const int INF = 0xfffffff; struct Edge{ int to, next, cap, flow; }edge[ maxm ];//注意是maxm int tol; int head[ maxn ]; int gap[ maxn ], dep[ maxn ], cur[ maxn ]; void init(){ tol = 0; memset( head, -1, sizeof( head ) ); } void addedge( int u, int v, int w, int rw = 0 ){ edge[ tol ].to = v; edge[ tol ].cap = w; edge[ tol ].flow = 0; edge[ tol ].next = head[ u ]; head[ u ] = tol++; edge[ tol ].to = u; edge[ tol ].cap = rw; edge[ tol ].flow = 0; edge[ tol ].next = head[ v ]; head[ v ] = tol++; } int Q[ maxn ]; void BFS( int start, int end ){ memset( dep, -1, sizeof( dep ) ); memset( gap, 0, sizeof( gap ) ); gap[ 0 ] = 1; int front = 0, rear = 0; dep[ end ] = 0; Q[ rear++ ] = end; while( front != rear ){ int u = Q[ front++ ]; for( int i = head[ u ]; i != -1; i = edge[ i ].next ){ int v = edge[ i ].to; if( dep[ v ] != -1 ) continue; Q[ rear++ ] = v; dep[ v ] = dep[ u ] + 1; gap[ dep[ v ] ]++; } } } int S[ maxn ]; int sap( int start, int end, int N ){ BFS( start, end ); memcpy( cur, head, sizeof( head ) ); int top = 0; int u = start; int ans = 0; while( dep[ start ] < N ){ if( u == end ){ int Min = INF; int inser; for( int i = 0; i < top; ++i ){ if( Min > edge[ S[ i ] ].cap - edge[ S[ i ] ].flow ){ Min = edge[ S[ i ] ].cap - edge[ S[ i ] ].flow; inser = i; } } for( int i = 0; i < top; ++i ){ edge[ S[ i ] ].flow += Min; edge[ S[ i ] ^ 1 ].flow -= Min; } ans += Min; top = inser; u = edge[ S[ top ] ^ 1 ].to; continue; } bool flag = false; int v; for( int i = cur[ u ]; i != -1; i = edge[ i ].next ){ v = edge[ i ].to; if( edge[ i ].cap - edge[ i ].flow && dep[ v ] + 1 == dep[ u ] ){ flag = true; cur[ u ] = i; break; } } if( flag ){ S[ top++ ] = cur[ u ]; u = v; continue; } int Min = N; for( int i = head[ u ]; i != -1; i = edge[ i ].next ){ if( edge[ i ].cap - edge[ i ].flow && dep[ edge[ i ].to ] < Min ){ Min = dep[ edge[ i ].to ]; cur[ u ] = i; } } gap[ dep[ u ] ]--; if( !gap[ dep[ u ] ] ) return ans; dep[ u ] = Min + 1; gap[ dep[ u ] ]++; if( u != start ) u = edge[ S[ --top ] ^ 1 ].to; } return ans; } int dir[ ][ 2 ] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; int main(){ int N, M, Case = 1; while( scanf( "%d%d", &N, &M ) != EOF ){ int s = N * M, t = N * M + 1; int n = N * M + 2, temp; init(); for( int i = 0; i < N; ++i ){ for( int j = 0; j < M; ++j ){ scanf( "%d", &temp ); if( temp == 2 ){ addedge( s, M * i + j, INF ); } if( temp == 1 ){ addedge( M * i + j, t, INF ); } for( int k = 0; k < 4; ++k ){ int x = i + dir[ k ][ 0 ]; int y = j + dir[ k ][ 1 ]; if( x >= 0 && x < N && y >= 0 && y < M ) addedge( M * i + j, M * x + y, 1 ); } } } printf( "Case %d:\n%d\n", Case++, sap( s, t, n ) ); } return 0; }
Pleasant sheep and big big wolf,布布扣,bubuko.com
时间: 2024-10-21 19:34:18