A-Matrix Equation_第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(济南)(重现赛)
自己写一个2维矩阵或者3维矩阵就可以发现对于每一列来说都是独立的,每一列的n个Cij都是都关系的,这就构成了一个n元一次方程组,其实这就是解一下这个方程组,但是他是问的有多少个矩阵,对于这个方程组构造出的矩阵来说,有多少自由元就说明有多少个Cij是可以任意取值的,也就是有1,2两种选择,不是自由元的就只能有1种;自由元是指系数都是0的未知数,自由元的个数就是高斯消元后0行的个数,所以用高斯消元就可以求出来;
又因为有运算是模2的,所以也就可以看成是异或型矩阵,那么运算方式就要稍微的发生以下变化,比如

上述图片来自2020icpc-济南站_琅歌的博客-CSDN博客
- #include
- using namespace std;
- #define endl '\n'
- #define int long long
- const int mod=998244353;
- const int inf=1e18;
- const int N = 2e5+100;
- const double eps=1e-8;
- int qpow(int a,int b)
- {
- int res=1;
- while(b)
- {
- if(b&1) res=res*a%mod;
- a=a*a%mod;
- b>>=1;
- }
- return res;
- }
- int getinv(int a){return qpow(a,mod-2LL);}
- int n;
- int a[220][220],b[220][220],d[220][220],fac[N];
- int gauss()
- {
- int newline=1;
- for(int k=1;k<=n;k++)
- {
- int p=newline;
- for(int i=newline+1;i<=n;i++)
- if(d[i][k]>d[p][k]) p=i;
- if(d[p][k]==0) continue;
- swap(d[newline],d[p]);
- for(int i=newline+1;i<=n;i++)
- {
- if(d[i][k]==0) continue;
- for(int j=1;j<=n;j++)
- d[i][j]^=d[newline][j];
- }
- newline++;
- }
- newline--;
- return n-newline;
- }
- void print()
- {
- cout<<"--------------------\n";
- for(int i=1;i<=n;i++)
- {
- for(int k=1;k<=n;k++)
- cout<
" "; - cout<
- }
- cout<<"--------------------\n";
- }
- signed main()
- {
- //ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
- cin>>n;
- fac[0]=1;
- for(int i=1;i<=100000;i++) fac[i]=fac[i-1]*2LL%mod;
- for(int i=1;i<=n;i++)
- for(int j=1;j<=n;j++) cin>>a[i][j],d[i][j]=a[i][j];
- for(int i=1;i<=n;i++)
- for(int j=1;j<=n;j++) cin>>b[i][j];
- int ans=1;
- for(int j=1;j<=n;j++)
- {
- for(int i=1;i<=n;i++)
- for(int k=1;k<=n;k++) d[i][k]=a[i][k];
- for(int i=1;i<=n;i++)
- d[i][i]=a[i][i]^b[i][j];
- //print();
- int res=gauss();
- //print();
- //cout<
- ans=ans*fac[res]%mod;
- //cout<
- //print();
- }
- cout<
- system("pause");
- return 0;
- }
借助这个题又回顾了一下高斯消元的东西,高斯消元其实就是大一学的矩阵的行列变换使得矩阵变为行阶梯型,步骤为:
1.设一变量newline代表进行到了第几行,最外层枚举列号k,内层枚举行i,找到最大的a[i][k]让其作为主元,将第i行与第newline行交换,如果最大的a[i][k]==0说明该变量是自由元,跳过去操作下一列;
2.将主元下面的数都消掉,就是行变换
3.操作结束后常数项/主元系数就是该未知数的解
- #include
- using namespace std;
- #define endl '\n'
- #define int long long
- const int mod=998244353;
- const int inf=1e18;
- const int N = 2e5+100;
- const double eps=1e-8;
- int qpow(int a,int b)
- {
- int res=1;
- while(b)
- {
- if(b&1) res=res*a%mod;
- a=a*a%mod;
- b>>=1;
- }
- return res;
- }
- int sgn(double x)
- {
- if(fabs(x)
return 0; - else if(x<0) return -1;
- else return 1;
- }
- int getinv(int a){return qpow(a,mod-2LL);}
- int n;
- double a[55][55];
- void gauss()
- {
- int nl=1;
- for(int k=1;k<=n;k++)
- {
- int p=nl;
- for(int i=nl+1;i<=n;i++)
- //找一列中最大的数作为主元
- if(sgn(a[p][k])==0) continue;
- //如果最大的数是0那这个变量是一个自由元,跳过
- swap(a[p],a[nl]);
- //将主元所在的行换到上面
- for(int i=1;i<=n;i++)
- {
- if(i==nl) continue;
- double tmp=a[i][k]/a[nl][k];
- for(int j=1;j<=n+1;j++)
- a[i][j]-=tmp*a[nl][j];
- //将该主元所在的列中的非零元素都消去,使得这一列中只有主元一个非零元素
- }
- nl++;
- }
- nl--;
- if(nl
- {
- //如果行数不够n,说明含有自由元
- for(int i=nl+1;i<=n;i++)
- {
- //如果常数项不为0说明是无解的
- if(a[i][n+1]!=0){cout<<"-1\n";return;}
- }
- //如果常数项是0说明是无穷解
- cout<<"0\n";return;
- }
- for(int i=1;i<=n;i++)
- {
- //常数项/主元系数就是未知数的解
- cout<<"x"<"="<
setprecision(2)<1]/a[i][i]< - }
- }
- signed main()
- {
- ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
- cin>>n;
- for(int i=1;i<=n;i++)
- for(int j=1;j<=n+1;j++) cin>>a[i][j];
- gauss();
- system("pause");
- return 0;
- }
P2962 [USACO09NOV]Lights G - dfs+高斯消元
这题也是异或方程组,可以发现假设每个灯按的次数是xi,那么对于每一个灯来说
xj1^xj2^xj3^...^xi^...^xjm=1,j[1...m]是与i相连的灯,n个灯就构成了n元异或方程组,高斯消元后,如果有自由元的存在就要枚举这个灯开着优还是关掉优,最后取一个最优值即可
题解 P2962 【[USACO09NOV]灯Lights】 - Youngsc_AFO 的博客 - 洛谷博客 (luogu.com.cn)
- #include
- using namespace std;
- #define endl '\n'
- #define int long long
- const int mod=998244353;
- const int inf=1e18;
- const int N = 4e5+100;
- const double eps=1e-8;
- int qpow(int a,int b)
- {
- int res=1;
- while(b)
- {
- if(b&1) res=res*a%mod;
- a=a*a%mod;
- b>>=1;
- }
- return res;
- }
- int sgn(double x)
- {
- if(fabs(x)
return 0; - else if(x<0) return -1;
- else return 1;
- }
- int getinv(int a){return qpow(a,mod-2LL);}
- int a[55][55],n,m;
- int vis[55],ans;
- void gauss()
- {
- int nl=1;
- for(int k=1;k<=n;k++)
- {
- int p=nl;
- if(a[p][k]==0) continue;
- swap(a[p],a[nl]);
- for(int i=1;i<=n;i++)
- {
- if(i==nl||a[i][k]==0) continue;
- for(int j=1;j<=n+1;j++)
- a[i][j]^=a[nl][j];
- }
- nl++;
- }
- nl--;
- }
- void dfs(int pos,int res)
- {
- if(ans<=res) return;
- if(pos==0)
- {
- ans=res;return;
- }
- int ma=n+1;
- for(int i=pos;i<=n;i++)
- {
- if(a[pos][i]){ma=i;break;}
- }
- if(ma<=n)
- {
- int num=a[pos][n+1];
- for(int i=ma+1;i<=n;i++)
- {
- if(a[pos][i]) num^=vis[i];
- }
- dfs(pos-1,res+num);
- }
- else
- {
- vis[pos]=0;
- dfs(pos-1,res);
- vis[pos]=1;
- dfs(pos-1,res+1);
- vis[pos]=0;
- }
- }
- void print()
- {
- cout<<"-----------------------------\n";
- for(int i=1;i<=n;i++)
- {
- for(int j=1;j<=n+1;j++)
- cout<
- }
- cout<<"------------------------------\n";
- }
- signed main()
- {
- //ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
- //freopen("in.txt","r",stdin);
- cin>>n>>m;
- for(int i=1;i<=n;i++) a[i][i]=a[i][n+1]=1;
- for(int i=1;i<=m;i++)
- {
- int u,v;cin>>u>>v;
- a[u][v]=a[v][u]=1;
- }
- //print();
- gauss();
- ans=inf;
- //print();
- dfs(n,0);
- cout<
- system("pause");
- return 0;
- }
P5027 Barracuda - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
根据题意列出方程然后枚举每一个方程是错误的,注意判断不合法的几个细节就可以,然后比较的时候一定要fabs,虽然都是正的,但是不加就是会wa,,,
- #include
- using namespace std;
- #define endl '\n'
- #define int long long
- const int mod=998244353;
- const int inf=1e18;
- const int N = 4e5+100;
- const double eps=1e-10;
- int qpow(int a,int b)
- {
- int res=1;
- while(b)
- {
- if(b&1) res=res*a%mod;
- a=a*a%mod;
- b>>=1;
- }
- return res;
- }
- int sgn(double x)
- {
- if(fabs(x)
return 0; - else if(x<0) return -1;
- else return 1;
- }
- bool integer(double s)
- {
- if(abs(round(s)-s)
return 1; - return 0;
- }
- int getinv(int a){return qpow(a,mod-2LL);}
- double a[105][105],b[105];
- int n;
- vector<int>v[105];
- int gauss()
- {
- int nl=1;
- for(int k=1;k<=n;k++)
- {
- int p=nl;
- for(int i=nl+1;i<=n;i++) if(fabs(a[p][k])<fabs(a[i][k])) p=i;
- //加上fabs才对,不知道为何,明明都是正的呀
- if(sgn(a[p][k])==0) continue;
- swap(a[p],a[nl]);
- for(int i=1;i<=n;i++)
- {
- if(i==nl) continue;
- double tmp=a[i][k]/a[nl][k];
- for(int j=1;j<=n+1;j++)
- a[i][j]-=tmp*a[nl][j];
- }
- nl++;
- }
- nl--;
- if(nl
return 0; - double res=0;
- int ma=n+1;
- for(int i=1;i<=n;i++)
- {
- double tmp=a[i][n+1]/a[i][i];
- if(tmp<0||sgn(a[i][n+1])==0) return 0;
- int ztmp=tmp;
- if(sgn(tmp-ztmp)!=0) return 0;
- if(res
- {
- res=tmp;ma=i;
- }
- }
- int cnt=0;
- for(int i=1;i<=n;i++)
- {
- double tmp=a[i][n+1]/a[i][i];
- if(sgn(res-tmp)==0) cnt++;
- }
- if(cnt>1) return 0;
- return ma;
- }
- void print()
- {
- cout<<"-----------------------------\n";
- for(int i=1;i<=n;i++)
- {
- for(int j=1;j<=n+1;j++)
- cout<
- }
- cout<<"------------------------------\n";
- }
- signed main()
- {
- //ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
- //freopen("in.txt","r",stdin);
- cin>>n;
- for(int i=1;i<=n+1;i++)
- {
- int m;cin>>m;
- for(int j=1;j<=m;j++)
- {
- int x;cin>>x;v[i].push_back(x);
- }
- cin>>b[i];
- }
- int ans=-1,mark=0;
- for(int i=1;i<=n+1;i++)
- {
- for(int j=1;j<=n;j++)
- for(int k=1;k<=n+1;k++) a[j][k]=0;
- int cnt=0;
- for(int j=1;j<=n+1;j++)
- {
- if(i==j)continue;
- cnt++;
- for(int k=0;k
size();k++) - {
- a[cnt][v[j][k]]=1;
- //cout<
- }
- a[cnt][n+1]=b[j];
- }
- //print();
- int flag=gauss();
- //print();
- if(flag)
- {
- mark++;
- ans=flag;
- if(mark>1){ans=-1;break;}
- }
- }
- if(ans==-1) cout<<"illegal\n";
- else cout<
- system("pause");
- return 0;
- }
P2447 [SDOI2010] 外星千足虫 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
一开始就构造成m行n+1列的方程组直接高斯消元,记录最大用到的行就是最小的K,N太大就用bitset优化,有一篇题解是不需要bitset的,但是我不知道他的做法为什么对就没采用,还是老老实实的用bitset吧
题解 P2447 【[SDOI2010]外星千足虫】 - YoungNeal 的博客 - 洛谷博客
- #include
- using namespace std;
- #define endl '\n'
- #define int long long
- const int mod=998244353;
- const int inf=1e18;
- const int N = 4e5+100;
- const double eps=1e-10;
- int qpow(int a,int b)
- {
- int res=1;
- while(b)
- {
- if(b&1) res=res*a%mod;
- a=a*a%mod;
- b>>=1;
- }
- return res;
- }
- int sgn(double x)
- {
- if(fabs(x)
return 0; - else if(x<0) return -1;
- else return 1;
- }
- bool integer(double s)
- {
- if(abs(round(s)-s)
return 1; - return 0;
- }
- int getinv(int a){return qpow(a,mod-2LL);}
- int n,m,b[2005],ans;
- char s[2005][1005];
- bitset<1005>a[2005];
- bool gauss()
- {
- ans=0;
- int nl=1;
- for(int k=1;k<=n;k++)
- {
- int p=nl;
- for(int i=nl;i<=m;i++) if(a[i][k]==1){p=i;break;}
- if(a[p][k]==0) return 0;
- ans=max(ans,p);
- swap(a[p],a[nl]);
- for(int i=1;i<=m;i++)
- {
-
- if(i==nl||a[i][k]==0) continue;
- // for(int j=k;j<=n+1;j++)
- // a[i][j]^=a[nl][j];
- a[i]^=a[nl];
- }
- nl++;
- }
- nl--;
- return nl>=n;
- }
- void print()
- {
- cout<<"-----------------------------\n";
- for(int i=1;i<=n;i++)
- {
- for(int j=1;j<=n+1;j++)
- cout<
- }
- cout<<"------------------------------\n";
- }
- signed main()
- {
- ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
- //freopen("in.txt","r",stdin);
- cin>>n>>m;
- for(int i=1;i<=m;i++)
- {
- cin>>(s[i]+1);
- for(int j=1;j<=n;j++) a[i][j]=(s[i][j]-'0');
- int x;cin>>x;
- a[i][n+1]=x;
- }
- if(gauss())
- {
- cout<
- for(int i=1;i<=n;i++)
- {
- if(a[i][n+1]^a[i][i]) cout<<"Earth\n";
- else cout<<"?y7M#\n";
- }
- }
- else cout<<"Cannot Determine\n";
- system("pause");
- return 0;
- }
P2973 [USACO10HOL]Driving Out the Piggies G - 高斯消元解方程组,概率
假设期望是经过这个点几次才会爆炸,那么期望其实是和概率在数值上是一样的了,也就是把每走一步的代价看作1,也就相当于在求期望了,f[i]表示经过了多少次i点会爆炸,然后根据题意就可以列出
f[i]=1+sum(f[j]*(1-P)*(1/in[j])) (i==1)
f[i]=sum(f[j]*(1-P)*(1/in[j])) (i!=1)
P是爆炸的概率,in[j]是j的度数,j可以到达i,j一共可以到达in[j]个点,j到达i的概率就是1/in[j],f[i]就可以通过j来转移,当i==1时因为一开始的起点就是1,所以1这个点一开始就经过了一次,所以要加上1
- #include
- using namespace std;
- #define endl '\n'
- #define int long long
- const int mod=998244353;
- const int inf=1e18;
- const int N = 4e5+100;
- const double eps=1e-10;
- int qpow(int a,int b)
- {
- int res=1;
- while(b)
- {
- if(b&1) res=res*a%mod;
- a=a*a%mod;
- b>>=1;
- }
- return res;
- }
- int sgn(double x)
- {
- if(fabs(x)
return 0; - else if(x<0) return -1;
- else return 1;
- }
- bool integer(double s)
- {
- if(abs(round(s)-s)
return 1; - return 0;
- }
- int getinv(int a){return qpow(a,mod-2LL);}
- int e[305][305],n,m,in[305];
- double p,q,a[305][305],P;
- void gauss()
- {
- int nl=1;
- for(int k=1;k<=n;k++)
- {
- int p=nl;
- if(sgn(a[p][k])==0) continue;
- swap(a[p],a[nl]);
- for(int i=1;i<=n;i++)
- {
- if(i==nl) continue;
- double tmp=a[i][k]/a[nl][k];
- for(int j=1;j<=n+1;j++)
- a[i][j]-=tmp*a[nl][j];
- }
- nl++;
- }
- for(int i=1;i<=n;i++)
- {
- double tmp=a[i][n+1]/a[i][i]*P;
- cout<
- }
- }
- signed main()
- {
- //ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
- //freopen("in.txt","r",stdin);
- cin>>n>>m>>p>>q;
- P=p/q;
- for(int i=1;i<=m;i++)
- {
- int u,v;
- cin>>u>>v;
- in[u]++;in[v]++;
- e[u][v]=e[v][u]=1;
- }
- for(int i=1;i<=n;i++) a[i][i]=1;
- for(int i=1;i<=n;i++)
- {
- for(int j=1;j<=n;j++)
- {
- if(e[i][j]) a[i][j]-=a[j][j]*(1.0-P)/in[j];
- }
- }
- a[1][n+1]=1;
- gauss();
- system("pause");
- return 0;
- }
-
相关阅读:
使用责任链模式实现登录风险控制
python统计应用
JAVA并发之谈谈你对AQS的理解
大一新生常踩的5大坑,轻则损失钱财,重则影响毕业
MATLAB——BP神经网络信号拟合程序
API 与 SDK 之间的区别
Naive UI 中使用message组件,在.vue文件之外使用
数仓GreenPlum中数据实时同步的方式
网络编程04-UDP的广播、组播
TypeScript中使用superagent
-
原文地址:https://blog.csdn.net/weixin_52621204/article/details/127707757