[浅谈] 高斯消元

P3389 【模板】高斯消元法

所谓高斯消元就是解个 n 元一次方程。
用矩阵记录每个方程的系数满足第 i 个方程:a[i][1]x1+a[i][2]x2++a[i][n]xn=a[i][n+1]

然后从消元,一个一个项消元,如消除 i 项。先选定一个此项系数绝对值最大的方程(这样可以减小误差?),然后将他的未知数 i 的系数化为 1 ,然后把剩下的方程与它相减消除未知数 i

最后一一带回字符串。实现的细节还得看代码。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
int n;
double mp[110][110],ans[110];
int main(){
	n=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n+1;j++)
			scanf("%lf",&mp[i][j]);
	for(int i=1;i<=n;i++){
		int rcd=i;
		for(int j=i+1;j<=n;j++)
			if(fabs(mp[rcd][i])<fabs(mp[j][i]))rcd=j;
		if(fabs(mp[rcd][i])<eps){
			printf("No Solution\n");
			return 0;
		}//找到系数最大的方程 
		if(i!=rcd)swap(mp[i],mp[rcd]);//换到当前行 
		double div=mp[i][i];//这个地方必须提出来,不然mp[i][i]会被修改
		for(int j=i;j<=n+1;j++)
			mp[i][j]/=div;//将此方程系数变为1 
		for(int j=i+1;j<=n;j++){
			div=mp[j][i];//这个地方必须提出来,不然mp[j][i]会被修改
			for(int k=i;k<=n+1;k++)
				mp[j][k]-=mp[i][k]*div;//消元 
		}
	}
	ans[n]=mp[n][n+1];
	for(int i=n-1;i>=1;i--){
		ans[i]=mp[i][n+1];
		for(int j=i+1;j<=n;j++)
			ans[i]-=mp[i][j]*ans[j];
	}
	for(int i=1;i<=n;i++)printf("%.2lf\n",ans[i]);
	return 0;
}

P4035 [JSOI2008]球形空间产生器

球心到所有点距离是一定的。我们把到第一个点的距离作为半径,球心到其他点的距离都等于这个半径:设球的圆心坐标用 b 表示:
(a122a1b1+b12)+(a222a2b2+b22)=(ai122ai1b1+b12)+(ai222i2b2+b22)
化简:
(2ai12a1)b1+(2ai22a2)b2=ai12+ai22a12a22
高斯消元即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
int n;
double mp[110][110],ans[110],tmp[50],now;
bool GSXY(){
	for(int i=1;i<=n;i++){
		int rcd=i;
		for(int j=i+1;j<=n;j++)
			if(fabs(mp[rcd][i])<fabs(mp[j][i]))rcd=j;
		if(fabs(mp[rcd][i])<eps){
			printf("No Solution\n");
			return false;
		}//找到系数最大的方程 
		if(i!=rcd)swap(mp[i],mp[rcd]);//换到当前行 
		double div=mp[i][i];
		for(int j=i;j<=n+1;j++)
			mp[i][j]/=div;//将此方程系数变为1 
		for(int j=i+1;j<=n;j++){
			div=mp[j][i];
			for(int k=i;k<=n+1;k++)
				mp[j][k]-=mp[i][k]*div;//消元 
		}
	}
	ans[n]=mp[n][n+1];
	for(int i=n-1;i>=1;i--){
		ans[i]=mp[i][n+1];
		for(int j=i+1;j<=n;j++)
			ans[i]-=mp[i][j]*ans[j];
	}
	return true;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)scanf("%lf",&tmp[i]);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			scanf("%lf",&now);
			mp[i][j]=2*now-2*tmp[j];
			mp[i][n+1]+=now*now-tmp[j]*tmp[j];
		}
	} 
	GSXY();
	for(int i=1;i<=n;i++)printf("%.3lf ",ans[i]);printf("\n");
	return 0;
}

P3232 [HNOI2013]游走

边太多了,我们考虑求每个点经过的期望次数。然后每个点都可以列出一个关于相邻点的 dp 式,然后就高斯消元。求出每条边期望经过次数,排序求解即可。

P3211 [HNOI2011]XOR和路径

异或难实现,考虑按位考虑,考虑对每一位求为 1 的期望。设 f[u] 表示 u>n 的路径的此位为 1 的期望。

P3265 [JLOI2015]装备购买

线性基,但是高斯消元。就如线性基 d[i] 存的是第 i 位为最高位且为 1 的数。我们存的是一组最前面没被消为 0 的未知数是 xi 的方程。
另外这题卡精度,得用逆元,我用的模数:1e6+33

P2447 [SDOI2010] 外星千足虫

这个条件显然可以用二分答案+高斯逆元,做完发现其实操作就是异或。但是会超时,因为只有 10 ,我们应该想到 bitset 优化(我没就想到)。

posted @   FJOI  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
点击右上角即可分享
微信分享提示