HEOI2016/TJOI2016 游戏

Link

Diffculty

算法难度6,思维难度5,代码难度6

Description

给定一个 n × m n\times m n×m 的地图,有空地,障碍,不能放炸弹的空地。

炸弹的威力不能穿过障碍,可以穿过不能放炸弹的空地。

要求放最多的炸弹,使得不存在炸弹能互相炸到。

1 ≤ n , m ≤ 50 1\le n,m\le 50 1n,m50

Solution

考虑取出行列中的极长连续不含障碍的段。

然后对于每个可以放炸弹的空地,变成一条边,从行点连向列点。

跑最大流即可。

#include
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
inline int read(){
	int x=0,f=1;char ch=' ';
	while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f==1?x:-x;
}
const int N=55,M=1e4+5;
int cnt,s,t,tot=-1,head[M],to[M],Next[M],flow[M];
inline void addedge(int x,int y,int l){
	to[++tot]=y;Next[tot]=head[x];head[x]=tot;flow[tot]=l;
	to[++tot]=x;Next[tot]=head[y];head[y]=tot;flow[tot]=0;
}
int d[M],q[M],cur[M];
inline bool bfs(){
	for(int i=0;i<=cnt;++i)d[i]=1e9;
	int l=1,r=1;q[1]=s;d[s]=0;
	while(l<=r){
		int x=q[l++];
		for(int i=head[x];~i;i=Next[i]){
			int u=to[i];
			if(flow[i] && d[u]>d[x]+1){
				d[u]=d[x]+1;
				q[++r]=u;
			}
		}
	}
	return d[t]<(int)1e9;
}
inline int dfs(int x,int a){
	if(x==t || !a)return a;
	int F=0,f;
	for(int &i=cur[x];~i;i=Next[i]){
		int u=to[i];
		if(flow[i] && d[u]==d[x]+1 && (f=dfs(u,min(a,flow[i])))>0){
			flow[i]-=f;
			flow[i^1]+=f;
			F+=f;
			a-=f;
			if(!a)return F;
		}
	}
	return F;
}
inline int dinic(){
	int F=0;
	while(bfs()){
		for(int i=0;i<=cnt;++i)cur[i]=head[i];
		F+=dfs(s,1e9);
	}
	return F;
}
int n,m,turn[200];
int id1[N][N],id2[N][N],a[N][N];
char ch[N];
int main(){
	memset(head,-1,sizeof head);
	turn['*']=0;turn['x']=1;turn['#']=2;
	n=read();m=read();s=0;
	for(int i=1;i<=n;++i){
		scanf("%s",ch+1);
		for(int j=1;j<=m;++j)a[i][j]=turn[(int)ch[j]];
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			if(a[i][j]==2)continue;
			if(j==1 || a[i][j-1]==2)id1[i][j]=++cnt;
			else id1[i][j]=id1[i][j-1];
		}
	}
	int cnt1=cnt;
	for(int i=1;i<=m;++i){
		for(int j=1;j<=n;++j){
			if(a[j][i]==2)continue;
			if(j==1 || a[j-1][i]==2)id2[j][i]=++cnt;
			else id2[j][i]=id2[j-1][i];
		}
	}
	t=++cnt;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			if(a[i][j]==0)
				addedge(id1[i][j],id2[i][j],1);
	for(int i=1;i<=cnt1;++i)addedge(s,i,1);
	for(int i=cnt1+1;i<=cnt;++i)addedge(i,t,1);
	printf("%d\n",dinic());
	return 0;
}

你可能感兴趣的:(HEOI2016/TJOI2016 游戏)