题目链接:
https://vjudge.net/contest/416227#problem/B
给定扫雷地图A,B,让你改变B中的某些方格,使总共的数字和与A中一致,且改动次数不超过总格数的一半。
我们可以换一个角度理解数字和:
我们可以把相邻的格子(相邻指的是有共同的端点)间连无向边,边上有权值
如果一个雷和一个没有雷的格子相邻,那么权值为1,如果这两个格子都有雷或者都没雷,那权值就为0。对所有的边权求和,结果就是所求的数字和。
这个角度跟场的势能的概念有点接近
从这个角度讲,重要的是相邻的两个格子的属性是否相同,给定一种地图,我们可以构造与其属性完全相反的地图,其数字和不变。
我们要通过改变B中某些格子的属性,使其数字和与A一致,不如构造成A或每个格子与A都相反的地图。
为了说明这种构造满足动次数不超过总格数的一半,需要证明一下
我们把A,B映射成两个2进制数x,y,每一位就代表一个格子有雷还是没有雷,设与A相反的图对应z
定义两个图之间的差异为(w(a,b)=sum_{i=0}^{nm-1}[(a\,xor\,b)\,and\,2^i>0])
那么(x\,xor\,z=111...111)
(w(x,y)+w(y,z)=sum_{i=0}^{nm-1}[(x\,xor\,y)\,and\,2^i>0]+sum_{i=0}^{nm-1}[(z\,xor\,y)\,and\,2^i>0]=sum_{i=0}^{nm-1}[(z\,xor\,y)\,and\,2^i>0]+[(x\,xor\,y)\,and\,2^i>0])
由于(x,z)的每一位都是不同的,因此([(z\,xor\,y)\,and\,2^i>0],[(x\,xor\,y)\,and\,2^i>0])有且仅有一个成立
故(w(x,y)+w(y,z)=nm)
(min(w(x,y),w(y,z))lefrac{nm}{2})
所以我们只要构造出A和A的相反图,再和B比较,取差异小的即可
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
char A[1010][1010];
char B[1010][1010];
char inv_A[1010][1010];
char inv(char ch)
{
if(ch=='.')return 'X';
return '.';
}
int comp(char map1[][1010],char map2[][1010],int n,int m)
{
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
ans+=(map1[i][j]!=map2[i][j]);
}
}
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",A[i]+1);
}
for(int i=1;i<=n;i++)
{
scanf("%s",B[i]+1);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)inv_A[i][j]=inv(A[i][j]);
}
int comp1=comp(A,B,n,m);
if(comp1*2<=n*m)
{
for(int i=1;i<=n;i++)
{
printf("%s
",A[i]+1);
}
}
else
{
for(int i=1;i<=n;i++)
{
printf("%s
",inv_A[i]+1);
}
}
}