高斯消元习题
高斯消元
- 概念
- 浮點數(shù)模板
- P3389 【模板】高斯消元法
- 異或方程組
- 模板
- 開關(guān)問題 POJ - 1830
- EXTENDED LIGHTS OUT
概念
- 自由變元:取非零行的首非零元所在列對應(yīng)的變元為約束變元,其余變元取作自由變元
比如 x1+x2+x3=3x_1+x_2+x_3=3x1?+x2?+x3?=3 ,這個式子的自由變元為 2 ,不確定變元為 3。因為這個式子中,當兩個變元確定之后,最后一個量也確定了。 - 列主元消去法:取當前列 rowrowrow 以下的最大值所在行與 rowrowrow 所在行交換,這樣可以將較大的數(shù)放在第row列,即除數(shù)的位置,從而減小誤差
浮點數(shù)模板
int gauss(double a[][maxn],int n,int m) {for(int row=1,col=1; row<=n&&col<=m; ++row,++col){int maxrow=row;for(int i=row+1; i<=n; ++i)if(fabs(a[i][col])>fabs(a[row][col])) maxrow=i;if(maxrow!=row){for(int i=col; i<=m+1; ++i)swap(a[row][i],a[maxrow][i]);}//if(a[row][col]==0) return -1;//存在自由變元for(int i=row+1; i<=n; ++i){double tmp=a[i][col]/a[row][col];for(int j=col; j<=m+1; ++j)a[i][j]-=a[row][j]*tmp;}}for(int i=m; i>=1; --i){double res=a[i][m+1];for(int j=i+1; j<=m; ++j)res-=a[i][j]*x[j];x[i]=res/a[i][i];}return 0; }P3389 【模板】高斯消元法
鏈接:https://www.luogu.com.cn/problem/P3389
#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn=110;int n; double a[maxn][maxn]; double x[maxn];int gauss(double a[][maxn],int n,int m) {for(int row=1,col=1;row<=n&&col<=m;++row,++col){int maxrow=row;for(int i=row+1;i<=n;++i)if(abs(a[i][col])>abs(a[row][col])) maxrow=i;if(maxrow!=row){for(int i=col;i<=m+1;++i)swap(a[row][i],a[maxrow][i]);}if(a[row][col]==0) return -1;//存在自由變元for(int i=row+1;i<=n;++i){double tmp=a[i][col]/a[row][col];for(int j=col;j<=m+1;++j)a[i][j]-=a[row][j]*tmp;}} for(int i=m;i>=1;--i){double res=a[i][m+1];for(int j=i+1;j<=m;++j)res-=a[i][j]*x[j];x[i]=res/a[i][i];}return 0; }int main() { scanf("%d",&n);for(int i=1;i<=n;++i)for(int j=1;j<=n+1;++j)scanf("%lf",&a[i][j]);int res=gauss(a,n,n);if(res==-1) puts("No Solution");else{for(int i=1;i<=n;++i)printf("%.2lf\n",x[i]);}return 0; }異或方程組
模板
int x[maxn]; int gauss(int a[][maxn],int n,int m) {int row,col;for(row=1,col=1; row<=n&&col<=m; ++row,++col){int maxrow=row;for(int i=row+1; i<=n; ++i)if(abs(a[i][col])>abs(a[row][col])) maxrow=i;if(maxrow!=row){for(int i=col; i<=m+1; ++i)swap(a[row][i],a[maxrow][i]);}if(a[row][col]==0){row--;continue;}for(int i=row+1; i<=n; ++i){if(a[i][col]!=0){for(int j=col; j<=m+1; ++j)a[i][j]^=a[row][j];}}}for(int i=row; i<=n; ++i)if(a[i][col]!=0) return -1;//存在無解的情況 if(row<m+1) return m-row+1;//返回自由變元的數(shù)量 for(int i=m; i>=1; --i){int res=a[i][m+1];for(int j=i+1; j<=m; ++j)if(a[i][j]!=0) res^=(a[i][j]&&x[j]);//&&替代了 *x[i]=(res&&a[i][i]);} }開關(guān)問題 POJ - 1830
鏈接:http://poj.org/problem?id=1830
題意:給定 n 盞燈的初始狀態(tài)和最終狀態(tài),每次開關(guān)一盞燈都會引起相關(guān)的燈的變化,問有多少種方案從初始狀態(tài)到達最終狀態(tài)
思路:高斯消元,第 i 行表示第 i 盞燈受 1 ~ n 個開關(guān)的影響情況。
- 比如, 1 0 1 1 1 表示當前燈受 x1,x3,x4x_1,x_3,x_4x1?,x3?,x4? 三盞燈的影響,并且累積狀態(tài)發(fā)生了改變
- 最終答案就是求自由變元的個數(shù) xxx,2x2^x2x 就是答案
EXTENDED LIGHTS OUT
鏈接:http://poj.org/problem?id=1222
題意:給出一個 5×65 \times 65×6 的 01 矩陣,每次選擇一個位置 (i,j)(i,j)(i,j) 會翻轉(zhuǎn)與它相鄰的 4 個點和它自己,請你輸出一種方案,使得矩陣全部翻轉(zhuǎn)為 0
思路: 類比上一題,30盞燈,每 i 行表示第 i 盞燈受到的其他燈的影響情況,最后一個值 val 表示是否需要改變。
#include <cstdio> #include <cmath> #include <algorithm> #include <cstring> #define ll long long using namespace std; const int maxn=35;int x[maxn]; int gauss(int a[][maxn],int n,int m) {int row,col;for(row=1,col=1; row<=n&&col<=m; ++row,++col){int maxrow=row;for(int i=row+1; i<=n; ++i)if(abs(a[i][col])>abs(a[row][col])) maxrow=i;if(maxrow!=row){for(int i=col; i<=m+1; ++i)swap(a[row][i],a[maxrow][i]);}if(a[row][col]==0){row--;continue;}for(int i=row+1; i<=n; ++i){if(a[i][col]!=0){for(int j=col; j<=m+1; ++j)a[i][j]^=a[row][j];}}}for(int i=row; i<=n; ++i)if(a[i][col]!=0) return -1;//存在無解的情況 if(row<m+1) return m-row+1;//返回自由變元的數(shù)量 for(int i=m; i>=1; --i){int res=a[i][m+1];for(int j=i+1; j<=m; ++j)if(a[i][j]!=0) res^=(a[i][j]&&x[j]);//&&替代了 *x[i]=(res&&a[i][i]);} } int t,a[maxn][maxn]; int main() {int Case=0;scanf("%d",&t);while(t--){memset(a,0,sizeof(a));memset(x,0,sizeof(x));for(int i=1; i<=30; ++i) scanf("%d",&a[i][31]);for(int i=1; i<=5; ++i){for(int j=1; j<=6; ++j){int col=(i-1)*6+j;a[col][col]=1;if(i>1) a[(i-2)*6+j][col]=1;if(i<5) a[i*6+j][col]=1;if(j>1) a[(i-1)*6+j-1][col]=1;if(j<6) a[(i-1)*6+j+1][col]=1;}}gauss(a,30,30);printf("PUZZLE #%d\n",++Case);for(int i=1; i<=30; ++i)printf("%d%c",x[i],i%6==0?'\n':' ');}return 0; }枚舉寫法
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> using namespace std; int t,x; int origin[10],ans[10],light[10]; void flip(int &x,int pos) {x^=(1<<pos-1); } int main() {scanf("%d",&t);int Cas=0;while(t--){memset(origin,0,sizeof(origin));for(int i=1;i<=5;++i){for(int j=1;j<=6;++j){scanf("%d",&x);if(x==1) origin[i]|=(1<<j-1); } }for(int i=0;i<64;++i){memcpy(light,origin,sizeof(origin));int choose=i;for(int j=1;j<=5;++j){ans[j]=choose;for(int k=1;k<=6;++k){if(choose>>k-1&1){if(k>1) flip(light[j],k-1);flip(light[j],k);if(k<6) flip(light[j],k+1);}}if(j<5)light[j+1]^=choose; choose=light[j];}if(light[5]==0){printf("PUZZLE #%d\n",++Cas);for(int j=1;j<=5;++j)for(int k=1;k<=6;++k)printf("%d%c",ans[j]>>k-1&1,k==6?'\n':' ');break;}} }return 0; }總結(jié)
- 上一篇: html代码在线解析,VIP在线解析HT
- 下一篇: 解决64位虚拟机安装和键盘FN快捷键问题