[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;
}