BZOJ2419: 电阻【高斯消元+基尔霍夫定律】

2419: 电阻

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 401 Solved: 178

Description

你突破了无数艰难险阻,终于解决了上面那道题,众神犇瞬间就震惊了。他们发现居然有人可以把那种非人类做的题目做出来。
他们一致同意,最后这道题不能再出数学题了。考虑到两位小盆友的状态,他们决定考考你的初中物理水平。
一个电路板,有 N 个接点,M 个电阻。电阻两端都在接点上,都告诉了你阻值。询问1 号点与N 号点的等效电阻是多少。
两位小盆友很聪明,他们拿出了一个欧姆表,瞬间就虐爆了…不过你也不甘落后,你肯定不会用这种投机取巧、误差巨大的方法,于是你看向了你的电脑。

Input

多组数据,输入直到文件结束
每组数据第一行两个整数N,M
接下来 M 行,每行三个非负整数 X,Y,R,表示电阻连接的两
接点和阻值。

Output

每组数据输出一行,一个实数,四舍五入到小数点后两位

Sample Input

2 1
1 2 1

Sample Output

1.00

【题解】

基尔霍夫定律???(这是啥玩意)

电流和流量有一样的性质,设路径电流I=1I=1,电势为μ\mu

根据基尔霍夫定理可得:

μiμjRi,j=0\large \sum {\mu_i-\mu_j \over R_{i,j}}=0

μ1μiRi,j=1\large \sum {\mu_1-\mu_i \over R_{i,j}}=1

μiμnRi,j=1\large \sum {\mu_i-\mu_n \over R_{i,j}}=1

我们设μn=0\large \mu_n=0

那么上式就是一个n-1元1次方程组,高斯消元即可。

【代码如下】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const double EXP=1e-8;
int n,m;double R[505][505],a[505][505];
void Build(){
	for(int i=1;i<n;i++)
	for(int j=1;j<=n;j++) a[i][i]+=R[i][j],a[i][j]-=R[i][j];
	a[1][n+1]=1;a[n][n]=1,a[n][n+1]=0;
}
double _abs(double x){return x<0?-x:x;}
bool Work(){
	for(int i=1;i<=n;i++){
		int k=i;double Del;
		for(int j=i;j<=n;j++) if(_abs(a[j][i])>_abs(a[k][i])) k=j;
		if(_abs(Del=a[k][i])<EXP) return 0;
		for(int j=i;j<=n+1;j++) swap(a[i][j],a[k][j]);
		for(int j=i;j<=n+1;j++) a[i][j]/=Del;
		for(k=1;k<=n;k++) if(k^i){
			Del=a[k][i];
			for(int j=i;j<=n+1;j++) a[k][j]-=a[i][j]*Del;
		}
	}
	return 1;
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		memset(a,0,sizeof(a)),memset(R,0,sizeof(R));
		for(int i=1,x,y,r;i<=m;i++){
			scanf("%d%d%d",&x,&y,&r);
			if(x!=y) R[x][y]+=1.0/r,R[y][x]+=1.0/r;
		}
		Build();Work();printf("%.2lf\n",a[1][n+1]);
	}
	return 0;
} 
posted @ 2019-03-13 08:05  XSamsara  阅读(285)  评论(0编辑  收藏  举报