HDU - 2732 Leapin‘ Lizards 拆点最大流+BFS 学好英语QAQ

题目链接

https://vjudge.net/problem/HDU-2732

题意

一个n*m矩阵,矩阵上有一些位置有方块,有的方块上有人,人的跳越距离为d,可以跳跃曼哈顿距离(abs(行差值)+abs(列差值)) 小于等于d的别的方块上。跳跃出迷宫即视为逃脱。每个方块有跳跃限制a,最多允许a次跳跃(从这个方块跳到别的方块减少一次)。问有几个人无法逃脱。

思路

所有方块拆成in和out,in向out连边,权为跳跃限制。s向有人的方块连边,权为1,对每个方块i做bfs,对于能在d步以内到达的方块j,将i的out向j的in连边,权为限制(其实比限制大的任何数都行)。在bfs的过程中判断一下能否跳出地图,可以的话把这个方块的out向t连边,权为限制,跑最大流,答案为总人数-最大流。

注意输出,no和1对应的是不加s和was,2以上对应的是加s和were。这破地方wa好几次,服了自己了。

代码

#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
using namespace std;
	typedef long long ll;
	const int inf=0x3f3f3f3f;
	const int maxn=2020;
	const int maxe=200010;
	//前向星部分 
	int head[maxn],cnt; 
	struct Edge{
    
    
		int v;
		int w;
		int next;
	}edge[maxe];
	
	//用于BFS 
	struct Node{
    
    
		int x,y,z;
	}node;
	//Dinic部分 
	int n,m,d,s,t,tot;
	ll maxflow;
	int deep[maxn];
	int now[maxe];
	//BFS部分 
	bool inq[30][30];	
	int dxy[][2]={
    
    {
    
    1,0},{
    
    -1,0},{
    
    0,1},{
    
    0,-1}};
	//迷宫情况 
	int gp[30][30];
	bool gp2[30][30];
	//总初始化 
	void init(){
    
    
		tot=0;
		memset(head,-1,sizeof(head));
		memset(gp,0,sizeof gp);
		memset(gp2,0,sizeof gp2);
		cnt=0;
		maxflow=0; 
		return ;	
	}
	//前向星加边 
	void add(int u,int v,int w){
    
    
		//if(v==t)
		//cout<<u<<" "<<v<<" "<<w<<endl;
  		edge[cnt].v=v;
		edge[cnt].w=w;
		edge[cnt].next=head[u];
		head[u]=cnt++;
	}
	//Dinic 
	inline bool bfs(){
    
    
    	memset(deep,0x3f,sizeof(deep));
    	queue<int>q;
    	q.push(s);deep[s] = 0;now[s] = head[s];
    	while(q.size()){
    
    
        	int x = q.front();q.pop();
        	for(int i=head[x];i!=-1;i=edge[i].next){
    
    
        	    int y=edge[i].v;
         	    if(edge[i].w>0&&deep[y]==inf){
    
    
         	    	q.push(y);
        	        now[y]=head[y];
         	       	deep[y]=deep[x]+1;
        	        if(y==t)	return 1;
				}
        	}
    	}
    	return 0;
	}

	ll dfs(int x,int flow){
    
    
    	if(x==t)	return flow;
    	ll ans = 0,k,i;
    	for(i=now[x];i!=-1&&flow;i=edge[i].next){
    
    
        	now[x]=i;
        	int y=edge[i].v;
        	if(edge[i].w>0&&(deep[y]==deep[x]+1)){
    
    
        	    k=dfs(y,min(flow,edge[i].w));
         		if(!k)	deep[y]=inf;
            	edge[i].w-=k;
            	edge[i^1].w+=k;
            	ans+=k;
            	flow-=k;
        	}
    	}
    	return ans;
	}	

	void dinic(){
    
    
    	while(bfs())
    	    maxflow+=dfs(s,inf);
	}
	//BFS部分 
	void find(int x,int y){
    
    
		memset(inq,0,sizeof inq);
		//拆点连边 
		add((x-1)*m+y,(x-1)*m+y+500,gp[x][y]);
		add((x-1)*m+y+500,(x-1)*m+y,0);
		queue<Node>q;
		q.push({
    
    x,y,0});
		inq[x][y]=1;
		//这个方块能否跳出迷宫 
		bool es=0;
		while(q.size()){
    
    
			node=q.front(),q.pop();
			if(node.z>d)
				continue;
			//方块i向j连边 
			if(gp[node.x][node.y]){
    
    
				add((x-1)*m+y+500,(node.x-1)*m+node.y,gp[x][y]);
				add((node.x-1)*m+node.y,(x-1)*m+y+500,0);
			}
			//四方向遍历 
			for(int i=0;i<4;i++){
    
    
				int xx=node.x+dxy[i][0],yy=node.y+dxy[i][1];
				if((xx<1||xx>n||yy<1||yy>m)&&node.z<d)
					es=1;//可以跳出 
				else if(inq[xx][yy]==0){
    
    
					inq[xx][yy]=1;
					q.push({
    
    xx,yy,node.z+1});
				}
			}
		}
		//可以跳出就向t连边 
		if(es){
    
    	
			add((x-1)*m+y+500,t,gp[x][y]);
			add(t,(x-1)*m+y+500,0);
		}
		
	}
	int main(){
    
    	
		int tn;
		scanf("%d\n",&tn);
		for(int _=1;_<=tn;_++){
    
    
			init();
			//输入处理 
			scanf("%d%d",&n,&d);
			getchar();
			m=1;
			char ch;
			ch=getchar();
			while(ch!='\n'){
    
    
				gp[1][m]=ch-'0';
				ch=getchar();
				m++;
			}
			m--;
			for(int i=2;i<=n;i++){
    
    
				for(int j=1;j<=m;j++){
    
    
					ch=getchar();
					gp[i][j]=ch-'0';
				}
				getchar();
			} 
			for(int i=1;i<=n;i++){
    
    
				for(int j=1;j<=m;j++){
    
    
					ch=getchar();
					if(ch=='L'){
    
    
						tot++;
						gp2[i][j]=1;
					}
				}
				getchar();
			}
			//s和t设成绝对不可能编号的点 
			s=1501,t=s+1;
			//1---n*m是方块in,501---n*m+500是方块out 
			//s向有人的块的in连边 
			for(int i=1;i<=n;i++){
    
    
				for(int j=1;j<=m;j++){
    
    
					if(gp2[i][j]){
    
    
						add(s,(i-1)*m+j,1);
						add((i-1)*m+j,s,0);
					}
				}
			}
			//对每个可以跳的方块跑bfs,in-out连边部分也放在了里面 
			for(int i=1;i<=n;i++){
    
    
				for(int j=1;j<=m;j++){
    
    
					if(gp[i][j]){
    
    
						find(i,j);
					}
				}
			}
			dinic();
			int ans=tot-maxflow;
			//输出一定仔细,除了名词单复数还有was和were的区别。 
			printf("Case #%d: ",_);
			if(!ans)
				printf("no lizard was left behind.\n");
			else if(ans==1)
				printf("1 lizard was left behind.\n");
			else
				printf("%d lizards were left behind.\n",ans);
		}
    	return 0;
	}

猜你喜欢

转载自blog.csdn.net/TheSunspot/article/details/108351188
今日推荐