链接: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 guess(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=n;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=guess(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;//返回自由变元的数量
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]);
}
}
链接:http://poj.org/problem?id=1830
题意:给定 n 盏灯的初始状态和最终状态,每次开关一盏灯都会引起相关的灯的变化,问有多少种方案从初始状态到达最终状态
思路:高斯消元,第 i 行表示第 i 盏灯受 1 ~ n 个开关的影响情况。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int maxn=35;
int guess(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;
return m-row+1;
}
int t,n,s[maxn],e[maxn],a[maxn][maxn];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1; i<=n; ++i) scanf("%d",&s[i]);
for(int i=1; i<=n; ++i) scanf("%d",&e[i]);
memset(a,0,sizeof(a));
int u,v;
while(scanf("%d%d",&u,&v)&&(u||v)) a[v][u]=1;
for(int i=1; i<=n; ++i) a[i][i]=1;
for(int i=1; i<=n; ++i) a[i][n+1]=s[i]^e[i];
int res=guess(a,n,n);
if(res==-1) puts("Oh,it's impossible~!!");
else printf("%d\n",(1<<res));
}
return 0;
}
链接:http://poj.org/problem?id=1222
题意:给出一个 5 × 6 5 \times 6 5×6 的 01 矩阵,每次选择一个位置 ( i , j ) (i,j) (i,j) 会翻转与它相邻的 4 个点和它自己,请你输出一种方案,使得矩阵全部翻转为 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;//返回自由变元的数量
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;
}