[TJOI2016 & HEOI2016] 游戏

[TJOI2016 & HEOI2016] 游戏

洛谷题目链接

本来以为是算法写错了,最后居然发现是读入错了。。。

题解

我们先假设没有硬石头,也就是说在图上的一些位置可以放炸弹,我们要求的就是最多的个数,我们以每行只能放一个,每列只能放一个为限制条件建二分图,即当当一个点放下时行列都无法在放其他点,也就是二分图最大匹配中每一侧点集互不关联,所以我们只要求这个二分图的最大匹配即可,可以用dinic或者匈牙利算法。

而这道题有硬石头所以我们需要考虑如何建二分图,我们可以以硬石头为分界线,将一行拆成多个段,建立多个节点,因为他们是互不影响的,同理对于列也是这样的,当我们建完图之后跑一遍二分图最大匹配,二分图用匈牙利是比较快的。

代码

#include<bits/stdc++.h>
using namespace std;
const int MN=4e3;
int n,m,x[55][55],y[55][55],tot,s,t,ans;
char mp[55][55];
int head[MN],cnt;
struct node{
	int nxt,to;
}e[MN<<1];
inline void add(int a,int b){
	e[++cnt].nxt=head[a],head[a]=cnt,e[cnt].to=b;
}
bool vis[MN];
int cur[MN];
bool dfs(int u) {
    for (int i=head[u];i;i=e[i].nxt){
    	int to=e[i].to;
        if (!vis[to]) {
            vis[to]=1;
            if (!cur[to]||dfs(cur[to])) {
                cur[to]=u;
                return 1;
            }
        }
	}	
    return 0;
}
inline char get() {
    char c;
	c=getchar(); 
	while (c!='*'&&c!='x'&&c!='#')c=getchar();
    return c;
}
int main(){
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			mp[i][j]=get();
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			if(mp[i][j]=='#')continue;
			if(j==1||mp[i][j-1]=='#')tot++;
			x[i][j]=tot;
		}
	}
	for(int j=1;j<=m;++j){
		for(int i=1;i<=n;++i){
			if(mp[i][j]=='#')continue;
			if(i==1||mp[i-1][j]=='#')tot++;
			y[i][j]=tot;
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			if(mp[i][j]!='*')continue;
			add(x[i][j],y[i][j]);
		}
	}
	for (int i = 1; i <= tot; i++) {
        memset(vis, 0, sizeof(vis));
        if (dfs(i)) ans++;
    }
	printf("%d\n",ans);
	return 0;
}
posted @ 2021-08-12 19:29  fanner_rick  阅读(35)  评论(0)    收藏  举报