今年多校遇到一道高斯消元模板题,当时没做,主要原因还是太菜,简单题都没做完。。。。。赛后回过头来刷题解说是高斯消元(这一直都是队友负责的),所以我还是一脸懵逼。队友说这题完全可以暴力,我只有一个字:哦。。。。。。。
入门题:
思路:已经有很多相关的博客写过题解,我就不累述了。关键的就是:
- A【30】(初始状态矩阵),B【30】【30】(根据操作列的方程组),X(方【30】程的解),由题意得A+BX=0,等价于A=BX;
- 一个灯最后的状态由上下左右和自身的操作决定的,而我们的x【30】解就是30个按钮的操作次数;比如第一个格子(0,0),他的状态由(0,0)(0,1),(1,0)决定,所以可列方程x(0*6+0)+x(0*6+1)+x(1*6+0)=原始状态
/************************************************************** Problem:poj 1222 EXTENDED LIGHTS OUT User: youmi Language: C++ Result: Accepted Time:16MS Memory:660K ****************************************************************/ //#pragma comment(linker, "/STACK:1024000000,1024000000") //#include<bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <stack> #include <set> #include <sstream> #include <cmath> #include <queue> #include <deque> #include <string> #include <vector> #define zeros(a) memset(a,0,sizeof(a)) #define ones(a) memset(a,-1,sizeof(a)) #define sc(a) scanf("%d",&a) #define sc2(a,b) scanf("%d%d",&a,&b) #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scs(a) scanf("%s",a) #define sclld(a) scanf("%I64d",&a) #define pt(a) printf("%d\n",a) #define ptlld(a) printf("%I64d\n",a) #define rep(i,from,to) for(int i=from;i<=to;i++) #define irep(i,to,from) for(int i=to;i>=from;i--) #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) #define lson (step<<1) #define rson (lson+1) #define eps 1e-6 #define oo 0x3fffffff #define TEST cout<<"*************************"<<endl const double pi=4*atan(1.0); using namespace std; typedef long long ll; template <typename T> inline void read(T &n) { char c; int flag = 1; for (c = getchar(); !(c >= '0' && c <= '9' || c == '-'); c = getchar()); if (c == '-') flag = -1, n = 0; else n = c - '0'; for (c = getchar(); c >= '0' && c <= '9'; c = getchar()) n = n * 10 + c - '0'; n *= flag; } template<class T> inline T gcd(T a,T b) { if(b==0) return a; return gcd(b,a%b); } template<class T> inline T lcm(T a,T b) { return a*b/gcd(a,b); } int Pow(int base, ll n, int mo) { if (n == 0) return 1; if (n == 1) return base % mo; int tmp = Pow(base, n >> 1, mo); tmp = (ll)tmp * tmp % mo; if (n & 1) tmp = (ll)tmp * base % mo; return tmp; } //*************************** int n,m; const int maxn=30+10; int a[maxn][maxn]; int x[maxn]; int fre[maxn]; int index; int kx[]={1,-1,0,0}; int ky[]={0,0,1,-1}; void debug(int rw,int cl) { rep(i,0,rw-1) { rep(j,0,cl-1) printf("%d ",a[i][j]); printf("\n"); } } bool is_out(int xx,int yy) { if(xx<0||yy<0||xx>4||yy>5) return true; return false; } void init() { memset(fre,1,sizeof(fre)); zeros(x); zeros(a); } int gauss(int rw,int cl) { int i,j,k; int mx=0; for(i=0,j=0;i<rw&&j<cl-1;i++,j++) { mx=i; for(k=i;k<rw;k++) { if(abs(a[k][j])>abs(a[mx][j])) mx=k; } if(mx!=i) { for(k=j;k<cl;k++) swap(a[mx][k],a[i][k]); } if(a[i][j]==0) { i--; continue; } for(k=i+1;k<rw;k++) { if(a[k][j]!=0) { /**int Lcm=lcm(a[k][j],a[i][j]); int ta=Lcm/a[i][j],tb=Lcm/a[k][j];*/ for(int t=j;t<cl;t++) { //a[k][t]=a[k][t]*ta-a[i][t]*tb; a[k][t]^=a[i][t]; } } } } //debug(30,31); /**for(k=i+1;k<rw;k++) { if(a[k][j]!=0) return -1;//no solution } if(i<rw)//infinite solution { for(k=i-1;k>=0;k--) { int num=0; for(int t=0;t<cl;t++) { if(a[k][t]!=0&&fre[t]) num++,index=t; } if(num>1) continue; int temp=a[k][cl-1]; for(int t=0;t<cl-1;t++) if(a[k][t]!=0&&index!=t) temp-=a[k][t]*x[t]; x[index]=temp/a[k][index]; fre[index]=0; } return rw-i; }*/ for(k=rw-1;k>=0;k--) { int temp=a[k][cl-1]; for(int t=k+1;t<cl-1;t++) temp^=a[k][t]&&x[t]; /**if(temp%a[k][k]) return -2;// float answer*/ x[k]=temp&&a[k][k]; } return 0; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int T_T; scanf("%d",&T_T); for(int kase=1;kase<=T_T;kase++) { printf("PUZZLE #%d\n",kase); init(); int temp=0; rep(i,0,4) rep(j,0,5) sc(a[i*6+j][30]); rep(i,0,4) { rep(j,0,5) { a[temp][i*6+j]=1; rep(k,0,3) { if(!is_out(i+kx[k],j+ky[k])) a[temp][(i+kx[k])*6+j+ky[k]]=1; } temp++; } } //debug(30,31); gauss(30,31); rep(i,0,4) { rep(j,0,5) printf("%d%c",x[i*6+j],j==5?'\n':' '); } } }
solution: 一个mod3版本的开关灯问题,对每个格子分别设操作了xi次,那么就可以列出一个n*m的方程组,然后高斯消元就可以了
/************************************************************** Problem:hdu 5755 Gambler Bo User: youmi Language: C++ Result: Accepted Time:483MS Memory:4828K solution: 一个mod3版本的开关灯问题,对每个格子分别设操作了xi次, 那么就可以列出一个n*m的方程组,然后高斯消元就可以了 ****************************************************************/ //#pragma comment(linker, "/STACK:1024000000,1024000000") //#include<bits/stdc++.h> #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <stack> #include <set> #include <sstream> #include <cmath> #include <queue> #include <deque> #include <string> #include <vector> #define zeros(a) memset(a,0,sizeof(a)) #define ones(a) memset(a,-1,sizeof(a)) #define sc(a) scanf("%d",&a) #define sc2(a,b) scanf("%d%d",&a,&b) #define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c) #define scs(a) scanf("%s",a) #define sclld(a) scanf("%I64d",&a) #define pt(a) printf("%d\n",a) #define ptlld(a) printf("%I64d\n",a) #define rep(i,from,to) for(int i=from;i<=to;i++) #define irep(i,to,from) for(int i=to;i>=from;i--) #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) #define lson (step<<1) #define rson (lson+1) #define eps 1e-6 #define oo 0x3fffffff #define TEST cout<<"*************************"<<endl const double pi=4*atan(1.0); using namespace std; typedef long long ll; template <typename T> inline void read(T &n) { char c; int flag = 1; for (c = getchar(); !(c >= '0' && c <= '9' || c == '-'); c = getchar()); if (c == '-') flag = -1, n = 0; else n = c - '0'; for (c = getchar(); c >= '0' && c <= '9'; c = getchar()) n = n * 10 + c - '0'; n *= flag; } template<class T> inline T gcd(T a,T b) { if(b==0) return a; return gcd(b,a%b); } template<class T> inline T lcm(T a,T b) { return a*b/gcd(a,b); } int Pow(int base, ll n, int mo) { if (n == 0) return 1; if (n == 1) return base % mo; int tmp = Pow(base, n >> 1, mo); tmp = (ll)tmp * tmp % mo; if (n & 1) tmp = (ll)tmp * base % mo; return tmp; } //*************************** int n,m; const int maxn=900+10; int a[maxn][maxn]; int x[maxn]; int fre[maxn]; int index; int kx[]={1,-1,0,0}; int ky[]={0,0,1,-1}; void debug(int rw,int cl) { rep(i,0,rw-1) { rep(j,0,cl-1) printf("%d ",a[i][j]); printf("\n"); } } bool is_out(int xx,int yy,int rw,int cl) { if(xx<0||yy<0||xx>=rw||yy>=cl) return true; return false; } void init() { memset(fre,1,sizeof(fre)); zeros(x); zeros(a); } int gauss(int rw,int cl) { int i,j,k; int mx=0; for(i=0,j=0;i<rw&&j<cl-1;i++,j++) { mx=i; for(k=i;k<rw;k++) { if(abs(a[k][j])>abs(a[mx][j])) mx=k; } if(mx!=i) { for(k=j;k<cl;k++) swap(a[mx][k],a[i][k]); } if(a[i][j]==0) { i--; continue; } for(k=i+1;k<rw;k++) { if(a[k][j]!=0) { int Lcm=lcm(a[k][j],a[i][j]); int ti=Lcm/a[i][j],tk=Lcm/a[k][j]; for(int t=j;t<cl;t++) { a[k][t]=((a[k][t]*tk-a[i][t]*ti)%3+3)%3; } } } } //debug(rw,cl); for(k=rw-1;k>=0;k--) { int temp=a[k][cl-1]%3; for(int t=k+1;t<cl-1;t++) temp=((temp-a[k][t]*x[t])%3+3)%3; x[k]=temp*a[k][k]%3; } return 0; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int T_T; scanf("%d",&T_T); for(int kase=1;kase<=T_T;kase++) { sc2(n,m); init(); int temp=0; rep(i,0,n-1) rep(j,0,m-1) { sc(a[i*m+j][n*m]); a[i*m+j][n*m]=(3-a[i*m+j][n*m])%3; } rep(i,0,n-1) { rep(j,0,m-1) { a[temp][i*m+j]=2; rep(k,0,3) { if(!is_out(i+kx[k],j+ky[k],n,m)) a[temp][(i+kx[k])*m+j+ky[k]]=1; } temp++; } } gauss(n*m,n*m+1); int cnt=0; rep(i,0,n-1) rep(j,0,m-1) if(x[i*m+j]) cnt+=x[i*m+j]; printf("%d\n",cnt); rep(i,0,n-1) { rep(j,0,m-1) { while(x[i*m+j]) { printf("%d %d\n",i+1,j+1); x[i*m+j]--; } } } } }
不为失败找借口,只为成功找方法