点灯问题。和上一篇差不多,只不过这次是一个方阵,一个灯被操作了一次之后四方取反。目标是求最少点多少次。
上篇忘说了,一个灯只有操作一次或零次是有意义的,两次相当于取了两次xor。这不废话吗。
把上一篇的影响内容改一改,然后求解的话,对于每个系数不为零的方程,第一个有系数的地方是主元,主元后面的有系数的都是自由元,不妨贪心全取0,那主元取0还是1就看等号右边了。记录每个灯的操作,系数全0的方程不管。
没了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #define dbg(x) cerr << #x << " = " << x <<endl 7 using namespace std; 8 typedef long long ll; 9 typedef double db; 10 typedef pair<int,int> pii; 11 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 12 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 16 template<typename T>inline T read(T&x){ 17 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 18 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 19 } 20 int A[33],bin[33],ans[33]; 21 int T,n=30,x,y,c; 22 inline void preprocess(){ 23 for(register int i=1;i<=n;++i){ 24 if(i-6>0)A[i]|=bin[i-7]; 25 if(i+6<=n)A[i]|=bin[i+5]; 26 if(i%6!=1)A[i]|=bin[i-2]; 27 if(i%6!=0)A[i]|=bin[i]; 28 A[i]|=bin[i-1]; 29 } 30 } 31 32 int main(){//freopen("test.in","r",stdin);freopen("test.ans","w",stdout); 33 for(register int i=0;i<=30;++i)bin[i]=1<<i; 34 read(T);for(register int tt=1;tt<=T;++tt){ 35 memset(ans,0,sizeof ans);memset(A,0,sizeof A); 36 for(register int i=1;i<=n;++i)read(x),A[i]|=x<<n; 37 preprocess(); 38 for(x=1,c=1;c<=n;++c){ 39 for(y=x;y<=n&&!(bin[c-1]&A[y]);++y); 40 if(y==n+1)continue; 41 swap(A[x],A[y]); 42 for(register int l=1;l<=n;++l)if((l^x)&&(A[l]&bin[c-1]))A[l]^=A[x]; 43 ++x; 44 } 45 for(register int i=1;i<x;++i)for(register int j=1;j<=n;++j)if(A[i]&bin[j-1]){ans[j]=A[i]>>n;break;} 46 printf("PUZZLE #%d ",tt); 47 for(register int i=1;i<=n;++i)printf("%d ",ans[i]),(i%6==0)&&printf(" "); 48 } 49 return 0; 50 }
终于知道小时候玩的游戏怎么破第100关了