【BZOJ2419】电阻(物理题)

点此看题面

大致题意: 一个电路板上有\(n\)个接点和\(m\)个电阻,给出每个电阻阻值及其在哪两个接点之间,求\(1\)与\(n\)两点间的等效电阻。

基尔霍夫方程组

基尔霍夫方程组应该是一个众所周知的东西,可以分为节点定律和回路定律。

一开始很\(naive\)地想去假设每个电阻的电流,结果发现似乎只能对于每个节点列出方程,而电阻数很可能超过节点数,无法得出解。

于是,只能去假设第\(i\)个电阻的电势为\(\varphi_i\),那么流经一个电阻\(R_{x,y}\)的电流可以看作\(\frac{\varphi_x-\varphi_y}{R_{x,y}}\)(此处暂且不考虑正负性)。

对于除\(1\)和\(n\)以外的每一个节点,有电流之和为零(\(1\)号点电流和为\(I_{total}\)),也就是:

\[\sum\frac{\varphi_i-\varphi_j}{R_{i,j}}=0 \]

然后我们不妨设\(\varphi_n=0,I_{total=1}\),则:对于\(1\)号点,直接修改右式的\(0\)为\(1\)即可;对于\(n\)号点,已知\(\varphi_n=0\),那么不用再列与它有关的方程,且可以直接从所有方程中将\(\varphi_n\)这一项删去。

接下来只要高斯消元,并得到最终答案\(R_{total}=\frac{\varphi_1-\varphi_n}{I_{total}}=\phi_1\)。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100
#define DB double
#define eps 1e-8
using namespace std;
int n,m;
namespace Gauss//高斯消元
{
	int S;DB a[N+5][N+5],v[N+5];I void swap(DB& x,DB& y) {DB t=x;x=y,y=t;}
	I void Clear() {memset(a,0,sizeof(a)),memset(v,0,sizeof(v));}
	I void Find(CI x)
	{
		if(fabs(a[x][x])>eps) return;RI i,j;for(i=x+1;fabs(a[i][x])<eps;++i);
		for(j=x;j<=S;++j) swap(a[x][j],a[i][j]);
	}
	I void Calc()
	{
		RI i,j,k;DB t;for(i=1;i<=S;++i) for(Find(i),j=i+1;j<=S;++j)
			for(v[j]+=(t=-a[j][i]/a[i][i])*v[i],k=i;k<=n;++k) a[j][k]+=t*a[i][k];
		for(i=S;i;--i) for(v[i]/=a[i][i],j=i-1;j;--j) v[j]-=a[j][i]*v[i];
	}
}using namespace Gauss;
int main()
{
	RI i,x,y,R;W(scanf("%d%d",&n,&m)==2)
	{
		for(Clear(),i=1;i<=m;++i) scanf("%d%d%d",&x,&y,&R),
			a[x][x]+=1.0/R,a[y][y]+=1.0/R,a[x][y]-=1.0/R,a[y][x]-=1.0/R;//确定方程系数
		v[1]=1,S=n-1,Calc(),printf("%.2lf\n",v[1]);//1号点右式为1,令S=n-1忽略第n项
	}return 0;
}
上一篇:【机器学习】数值分析(1)—— 任意方程求根


下一篇:四校省选模拟第一轮Day1