观察到这个数据范围,显然不可能真的存这么大的邻接矩阵。
进一步发现,题目要求正方形矩阵的边长为偶数,并且里面的1为奇数
这启发了我们,因为边长为4的一定要用边长为2的拼接起来,这样边长为4的里面一定是偶数个1
因此直接特判掉n>=4的答案
剩下只有n==2,和n==3。
对于n==2,我们发现因为每列只能是奇偶奇偶,或者是偶奇偶奇。因此我们就判断这两种情况取一个最小值
对于n==3,可以发现这是经典的网格图状压,也就是玉米田问题,因为种类只有8,我们先计算不冲突的情况,之后对于枚举每一列,求出合法状态
最终的答案就是每种状态取min
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; typedef pair<int,pll> plll; const int N=5e5+10; const int mod=1e9+7; char s[5][N]; int f[N][16]; vector<int> g[N]; //判断是否成立 bool check(int a,int b){ int a1=(a>>0)&1,b1=(b>>0)&1; int a2=(a>>1)&1,b2=(b>>1)&1; int a3=(a>>2)&1,b3=(b>>2)&1; if((a1+a2+b1+b2)%2==0) return false; if((a2+a3+b2+b3)%2==0) return false; return true; } //计算交换代价 int cal(int a,int b){ int a1=s[1][a],b1=(b>>0)&1; int a2=s[2][a],b2=(b>>1)&1; int a3=s[3][a],b3=(b>>2)&1; int ans=0; if(a1!=b1) ans++; if(a2!=b2) ans++; if(a3!=b3) ans++; return ans; } int main(){ ios::sync_with_stdio(false); int n,m; cin>>n>>m; int i,j; if(n==1){ cout<<0<<endl; } else if(n>=4){ cout<<-1<<endl; } else{ int i,j; for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ char c; cin>>c; s[i][j]=c-'0'; } } if(n==2){ int ans1=0,ans2=0; for(i=1;i<=m;i++){ int tmp=i&1; if(s[1][i]^s[2][i]!=tmp) ans1++; } for(i=1;i<=m;i++){ int tmp=(i+1)&1; if(s[1][i]^s[2][i]!=tmp) ans2++; } cout<<min(ans1,ans2)<<endl; } else{ for(i=0;i<8;i++){ for(j=0;j<8;j++){ if(check(i,j)) g[i].push_back(j); } } for(i=0;i<8;i++){ f[1][i]=cal(1,i); } for(i=2;i<=m;i++){ for(j=0;j<8;j++){ f[i][j]=1e9; for(auto x:g[j]){ f[i][j]=min(f[i][j],f[i-1][x]+cal(i,j)); } } } int ans=1e9; for(i=0;i<8;i++){ ans=min(ans,f[m][i]); } cout<<ans<<endl; } } return 0; }