习题:
Milo正聚精会神的组建自己的圣诞集市,他将把这个集市组建成整个欧洲最好的圣诞集市。晚上结束,到关灯的时间了,但有些人相当无礼,并没有关掉桌上的灯。由于电费越来越贵,Milo希望所有的灯都能很快的关掉,为此,他使用了传奇电子平板电脑(LEET)来达到这个目的,但他同时也需要你的帮助。
Milo的圣诞集市有N行,每行有N个摊位。在LEET上,Milo有两个按钮:
·按下第一个按钮,Milo想象出第x行,然后打开已关闭的第x行的每个灯,同时关闭第x行的每个已经打开的灯。
·按下第二个按钮,Milo想象出第x列,然后打开已关闭的第x列的每个灯,同时关闭第x列的每个已经打开的灯。
通过按压自己的肚脐(第三个按钮),Milo将决定走到一个特定的摊位,并亲自打开(或关闭)这个摊位的灯。现在的问题是,他的腿受伤了,为了避免肺栓塞,医生规定他“第三个按钮”最多只能使用K次(K≤N),幸运的是,第一个按钮和第二个按钮可以无限次使用。
请问,Milo有没有可能关掉所有摊位上的灯。
输入格式
第一行输入两个数N和K,表示摊位的行数和Milo能够使用第三个按钮的个数。(1≤N≤1000,0≤K≤N)
接下来的N行,每行N个字母,这些字母由‘x’和‘o’组成,其中,‘x’表示这个摊位的灯已经关闭,‘o’表示这个摊位的灯还开着。
输出格式
如果所有的灯能够全部关闭,输出“DA”。否则,输出“NE”。
样例
样例输入1
2 0
ox
ox
样例输出1
DA
样例输入2
3 1
ooo
xoo
oox
样例输出2
NE
样例输入3
4 2
oxxo
xxox
oxoo
oxxo
样例输出3
DA
思路:
首先有一点我们是可以明确的,第一个操作针对一行只会使用一次,第二个操作针对一列只会使用一次,第三个操作针对每一个格子只会使用一次。明白这点之后,我们再次考虑两行的状态,将这两行转换成二进制,再进行异或,如果异或后这一位为0,则证明这两个灯状态是一样的,说明我们不需要对这两个灯进行第三个操作,反之,则需要进行,同时这个操作是必须进行的。
代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int k;
int tot;
char c[1005][1005];
bool f=0;
bitset<1005> a[1005];
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>(c[i]+1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(c[i][j]=='o')
a[i].set(j);
}
}
if(k==n)
{
for(int i=1;i<=n;i++)
{
a[1].flip(i);
int flag=0;
for(int j=2;j<=n;j++)
{
a[0]=a[1]^a[j];
int tmp=B[0].count();
if(min(tmp,n-tmp)!=1)
{
flag=1;
break;
}
}
if(!flag)
{
cout<<"DA";
return 0;
}
a[1].flip(i);
}
}
for(int i=1;i<=n;i++)
{
int s=0;
for(int j=i+1;j<=n;j++)
{
a[0]=a[i]^a[j];
s=s+min(a[0].count(),n-a[0].count());
}
if(s<=k)
{
f=1;
break;
}
}
if(f)
cout<<"DA";
else
cout<<"NE";
return 0;
}