刚开始的时候考虑过各种暴力,不过似乎都太复杂了以至于写着写着就出错了或者写不下去了。这题其实有非常简便的做法。对于矩阵中的每一列,如果在该列的某一行处是”#”,那么在选中该列的同时该行也是一定要同时选中的。那么,对于任意的两列i,j,如果他们需要选中的行一样,OK,没问题,这两列可以在同一次选择中被选中。但是,如果i,j需要选择的行不一样,那么他们肯定就不能在同一次中选择了,否则的话这两列肯定会多出来额外的“#”。那么,对于任意两列不是同一次选中的列,他们之间如果需要选中的行又有重复的话,那么肯定就不行了,因为每行只能被选中一次。最后,为了快速表示每一列的状态,我们可以用一个二进制数来表示。
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
#include<queue>
#include<set>
#include<vector>
using namespace std;
typedef long long ll;
ll hang[60];
int main()
{
string mp[60];
int n,m,i,j,k;
cin>>n>>m;
set<ll>s;
for(i=1;i<=n;i++)cin>>mp[i];
for(i=0;i<m;i++){
for(j=1;j<=n;j++){
if(mp[j][i]=='#')
hang[i]|=(1ll<<j);//代表每一列需要的行的状态
}
s.insert(hang[i]);//去重
}
vector<ll>pos;
for(auto j=s.begin();j!=s.end();j++){
pos.push_back(*j);
}
for(i=0;i<pos.size()-1;i++){
for(j=i+1;j<pos.size();j++){
if(pos[i]&pos[j]){
cout<<"NO"<<endl;return 0;
}
}
}
cout<<"YES"<<endl;
return 0;
}
由于本题数据范围非常小,所以不查重暴力枚举也能过:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
ll a[60];
char s[60];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%s",s+1);
for(int j=1;j<=m;++j)
a[i]=(a[i]<<1|(s[j]=='#'));
}
for(int i=1;i<=n;++i)
for(int j=1+i;j<=n;++j)
if((a[i]!=a[j])&&(a[i]&a[j]))
{
puts("No");
return 0;
}
puts("Yes");
}