• Pleasant sheep and big big wolf


    点击打开链接

    题目:在一个N * M 的矩阵草原上,分布着羊和狼。每一个格子仅仅能存在0或1仅仅动物。如今要用栅栏将全部的狼和羊分开。问怎么放,栅栏数放的最少,求出个数?

    解析:将狼群看作一个集合,羊群看作一个集合。然后设置源点和汇点,将两点至存在动物的点的距离赋值为1,构图,因为求得是栅栏数,从存在动物的位置向四周发散点赋值为1,即该方向放置一个栅栏。然后能够发现变成了求最小割,即求出最大流。须要注意的是,因为数据比較大,200 * 200。假设设置源点和汇点相差较大(即s = 0,e = n * m ),easyTLE.

    #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:
    %d
    ", Case++, sap( s, t, n ) );
    	}
    	return 0;
    } 	 
    


  • 相关阅读:
    knowledge_maven
    problems_springboot
    problems_halo
    skills_oracle
    hive启动报错(整合spark)
    根据父ID聚合
    sql2005数据库远程备份
    waitfor的使用
    CTE+操作性语句(删除无主键的相同的多行数据)+CTE操作技巧
    SQL中的CTE,查询所有的子集(子集的子集)比游标效率高
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7055266.html
Copyright © 2020-2023  润新知