题目镜像
https://codeforces.ml/contest/1345/problem/D
题意
在一个格子图上,有黑白两种格子。初始时某些格子上有S棋子或N棋子,或两个都有一些。每次N棋子都会向某个与其同行同列的S棋子动一格。S棋子不可能动。要求构造一格初始的NS棋子的填法,满足下面条件:
1.每行每列都至少一个S棋子。
2.无论N棋子怎么走都不会走到白格子上去。
3.对每个黑格子,存在某一种N棋子走动的方案使得某个N棋子能走到这个黑格子上。
给定黑白地图,输出最少的N棋子数(S棋子不限)
思路
可以发现每种合法方案一定满足一些性质:
1.每个黑色的连通块至少一个N。
2.每个黑连通块的N必须且只能在本连通块内走到所有格子。(黑连通块全放上S就能保证走遍所有本连通块格子)。
3.为满足2,任意行列都只能有一段连续的黑格,不能有黑格夹住白格子的情况。
4.如果要在白格子填S的话,这个白格子所在行列都要纯白。
这样如果存在答案,就是连通块的数目
妈的我4情况没考虑清楚,以为白格子不能填S,WA17到怀疑人生。
代码
#include<cstdio>
#include<cstring>
using namespace std;
const int NN=1010;
int dei[4]={1,-1,0,0};
int dej[4]={0,0,1,-1};
int vis[NN][NN];
char a[NN][NN];
int n,m;
int pd(int x,int y){
if((x<1)||(x>n)||(y<1)||(y>m))return 0;
if(vis[x][y])return 0;
if(a[x][y]=='.')return 0;
return 1;
}
struct Node{
int i,j;
}q[NN*NN];
int ans=0;
int fi[NN],fj[NN];
int markk(int x,int y){
if(fi[x]!=0&&fi[x]!=ans){
return 0;
}
else fi[x]=ans;
if(fj[y]!=0&&fj[y]!=ans){
return 0;
}
else fj[y]=ans;
return 1;
}
int bfs(int sti,int stj){
int head=1,tail=0;
q[++tail].i=sti;
q[tail].j=stj;
vis[sti][stj]=1;
int temp=markk(sti,stj);
if(temp==0)return -1;
while(head<=tail){
Node cur=q[head];
for(int i=0;i<4;i++){
Node neww;neww.i=cur.i+dei[i];neww.j=cur.j+dej[i];
if(pd(neww.i,neww.j)==1){
q[++tail]=neww;
vis[neww.i][neww.j]=1;
temp=markk(neww.i,neww.j);
if(temp==0)return -1;
}
}
head++;
}
return 1;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",a[i]+1);
}
int can=1;
int hav1=0;
for(int i=1;i<=n;i++){
int l=n+1,r=0;
for(int j=1;j<=m;j++){
if(i==1&&a[i][j]=='#')hav1=1;
if(a[i][j]=='#'){l=j;break;}
}
for(int j=m;j>=1;j--){
if(a[i][j]=='#'){r=j;break;}
}
if(l<r){
for(int j=l+1;j<r;j++){
if(a[i][j]=='.'){
can=-1;
break;
}
}
}
if(can==-1)break;
}
if(can==-1){
//if(n==1000&&m==1000&&hav1==0)printf("1");
printf("-1\n");
return 0;
}
for(int j=1;j<=m;j++){
int l=n+1,r=0;
for(int i=1;i<=n;i++){
if(a[i][j]=='#'){l=i;break;}
}
for(int i=n;i>=1;i--){
if(a[i][j]=='#'){r=i;break;}
}
if(l<r){
for(int i=l+1;i<r;i++){
if(a[i][j]=='.'){
can=-1;
break;
}
}
}
if(can==-1)break;
}
if(can==-1){
//if(n==1000&&m==1000&&hav1==0)printf("2");
printf("-1\n");
return 0;
}
ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!vis[i][j]&&a[i][j]=='#'){
ans++;
int res=bfs(i,j);
if(res==-1){
ans=-1;
break;
}
}
}
}
if(ans==0){printf("0\n");return 0;}
int cant1=0,cant2=0;
for(int i=1;i<=n;i++)if(fi[i]==0){
cant1=1;
break;
}
if(ans>=0)for(int i=1;i<=m;i++)if(fj[i]==0){
cant2=1;
break;
}
if(cant1+cant2==1){
ans=-1;
}
if(ans>=0){
printf("%d\n",ans);
}
else{
printf("-1\n");
}
return 0;
}