zoukankan      html  css  js  c++  java
  • AtCoder

    Problem Statement

    There is a pond with a rectangular shape. The pond is divided into a grid with H rows and W columns of squares. We will denote the square at the i-th row from the top and j-th column from the left by (ij).

    Some of the squares in the pond contains a lotus leaf floating on the water. On one of those leaves, S, there is a frog trying to get to another leaf T. The state of square (ij) is given to you by a character aij, as follows:

    • . : A square without a leaf.
    • o : A square with a leaf floating on the water.
    • S : A square with the leaf S.
    • T : A square with the leaf T.

    The frog will repeatedly perform the following action to get to the leaf T: "jump to a leaf that is in the same row or the same column as the leaf where the frog is currently located."

    Snuke is trying to remove some of the leaves, other than S and T, so that the frog cannot get to the leaf T. Determine whether this objective is achievable. If it is achievable, find the minimum necessary number of leaves to remove.

    Constraints
    • 2H,W100
    • aij is ., o, S or T.
    • There is exactly one S among aij.
    • There is exactly one T among aij.
    Input

    Input is given from Standard Input in the following format:

    H W
    a11  a1W
    :
    aH1  aHW
    
    Output

    If the objective is achievable, print the minimum necessary number of leaves to remove. Otherwise, print -1 instead.

    Sample Input 1
    3 3
    S.o
    .o.
    o.T
    
    Sample Output 1
    2
    

    Remove the upper-right and lower-left leaves.

    Sample Input 2
    3 4
    S...
    .oo.
    ...T
    
    Sample Output 2
    0
    
    Sample Input 3
    4 3
    .S.
    .o.
    .o.
    .T.
    
    Sample Output 3
    -1
    
    Sample Input 4
    10 10
    .o...o..o.
    ....o.....
    ....oo.oo.
    ..oooo..o.
    ....oo....
    ..o..o....
    o..o....So
    o....T....
    ....o.....
    ........oo
    
    Sample Output 4
    5


    非常神奇的二分图建模!
    我们把行和列分别看成二分图两边的一排节点,那么我们的任务其实就是找到一个最小割,使得从S 的行或列 走不到 T的行或列。
    所以对于原图中的一片荷叶(i,j) ,我们就在二分图中添加 无向边 行i to 列j,再连 S 到 S行,S列 ; T行,T列到T。容量都是inf。

    这样原图中的最小割就是答案了,如果答案>=inf那么无解,说明S,T在同一行或者同一列。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int maxn=305,inf=1e8;
    #define pb push_back
    struct lines{
    	int to,flow,cap;
    }l[maxn*maxn*5];
    vector<int> g[maxn];
    int cur[maxn],d[maxn],t=-1,S,T;
    bool v[maxn];
    
    inline void add(int from,int to,int cap){
    	l[++t]=(lines){to,0,cap},g[from].pb(t);
    	l[++t]=(lines){from,0,0},g[to].pb(t);
    }
    
    inline bool BFS(){
    	memset(v,0,sizeof(v)),v[S]=1,d[S]=0;
    	queue<int> q; q.push(S);
    	int x; lines e;
    	
    	while(!q.empty()){
    		x=q.front(),q.pop();
    		for(int i=g[x].size()-1;i>=0;i--){
    			e=l[g[x][i]];
    			if(e.flow<e.cap&&!v[e.to]) v[e.to]=1,d[e.to]=d[x]+1,q.push(e.to);
    		}
    	}
    	
    	return v[T];
    }
    
    int dfs(int x,int A){
    	if(x==T||!A) return A;
    	int flow=0,f,sz=g[x].size();
    	for(int &i=cur[x];i<sz;i++){
    		lines &e=l[g[x][i]];
    		if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(e.cap-e.flow,A)))){
    			A-=f,flow+=f;
    			e.flow+=f,l[g[x][i]^1].flow-=f;
    			if(!A) break;
    		}
    	}
    	
    	return flow;
    }
    
    inline int max_flow(){
    	int an=0;
    	while(BFS()){
    		memset(cur,0,sizeof(cur));
    		an+=dfs(S,inf);
    	}
    	return an;
    }
    
    int n,m;
    char ch;
    
    int main(){
    	scanf("%d%d",&n,&m),S=0,T=n+m+1;
    	for(int i=1;i<=n;i++)
    	    for(int j=1;j<=m;j++){
    	    	ch=getchar();
    	    	while(ch!='.'&&ch!='o'&&ch!='S'&&ch!='T') ch=getchar();
    	    	if(ch!='.') add(i,j+n,1),add(j+n,i,1);
    	    	if(ch=='S') add(S,i,inf),add(S,j+n,inf);
    	    	else if(ch=='T') add(i,T,inf),add(j+n,T,inf);
    		}
    	
    	int ans=max_flow();
    	if(ans>=inf) puts("-1");
    	else printf("%d
    ",ans);
    	
    	return 0;
    }
    
     
  • 相关阅读:
    转载:史上最全|阿里那些牛逼带闪电的开源工具,你知道几个?
    互怼、IPO、雷潮、寒冬,2018 互联网圈的那些事儿
    微信迎来又一次重大改版 7.0 版本
    公众号文章目录
    聊几个与赚钱相关的小事情
    使用docker Registry快速搭建私有镜像仓库
    开源组件ELK日志系统配置与管理
    Mysql MHA高可用集群架构
    强大的开源企业级数据监控利器Lepus安装与配置管理
    关于下载gitbash客户端
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9101178.html
Copyright © 2011-2022 走看看