Electric resistance

280 篇文章 1 订阅

题目

传送门 to VJ

题目概要
给你一个电路图,求 1 1 1 号节点到 n n n 号节点的总电阻是多少。

数据范围与约定
数据组数 T ≤ 100 , 1 < n ≤ 50 , 0 < T\le 100,1<n\le 50,0< T100,1<n50,0< 边的数量 m ≤ 2000 , 1 ≤ m\le 2000,1\le m2000,1 电阻阻值 R ≤ 1 0 4 R\le 10^4 R104 。图是联通的简单图。

思路

众所周知,电压来源于电势差。

所以假设每个节点的电势即可。然后利用流入电流 = = = 流出电流建立方程即可。

可以规定 1 1 1 号节点的电势为 1 0 4 v 10^4\tt{v} 104v n n n 号节点的电势为 0 v 0\tt{v} 0v

然后利用欧姆定律, R = U I R=\frac{U}{I} R=IU 即可计算。

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
bool lessThan(double a,double b){
	return a+1e-6 < b;
}
bool equalsTo(double a,double b){
	return lessThan(a,b) and lessThan(b,a);
}

const int MaxN = 55;
struct Matrix{
	double a[MaxN][MaxN];
	int n, m;
	Matrix(){ this->clear(); }
	void clear(){ memset(a,0,sizeof a); }
	bool Gauss(){
		for(int i=1,cal=1; cal<m and i<=n; ++cal){
			int id = i; // 第i行
			for(int j=i+1; j<=n; ++j)
				if(fabs(a[id][cal]) < fabs(a[j][cal]))
					id = j; // 找绝对值最大的一行
			if(id != i) swap(a[i],a[id]);
			if(equalsTo(a[i][cal],0)) continue;
			for(int j=1; j<=n; ++j) if(i != j)
				for(int k=m; k>=cal; --k) // f = a[j][cal]/a[i][cal]
					a[j][k] -= a[i][k]*a[j][cal]/a[i][cal];
			for(int j=m; j>=cal; --j)
				a[i][j] /= a[i][cal];
			++ i; // 处理下一行
		}
		for(int i=m; i<=n; ++i)
			if(not equalsTo(a[i][m],0))
				return false; // 无解
		return true; // 有至少一个解
	}
	void paint(){
		for(int i=1; i<=n; ++i)
			for(int j=1; j<=m; ++j)
				printf("%f%c",a[i][j],j==m?'\n':' ');
	}
} mat;

int resistance[MaxN][MaxN];
void work(){
	mat.clear(); // 进行清零
	memset(resistance,0,MaxN*MaxN<<2);
	scanf("%d %d",&mat.n,&mat.m);
	for(int i=1,x,y,z; i<=mat.m; ++i){
		scanf("%d %d %d",&x,&y,&z);
		resistance[x][y] = z;
		resistance[y][x] = z;
	}
	for(int i=2; i<mat.n; ++i)
		for(int j=1; j<=mat.n; ++j){
			if(i == j or resistance[i][j] == 0)
				continue;
			mat.a[i][j] = 1.0/resistance[i][j];
			mat.a[i][i] += -mat.a[i][j];
		}
	mat.m = mat.n+1; // 恰好有解的矩阵
	mat.a[1][1] = 1, mat.a[1][mat.m] = 10000;
	// 规定U1 = 10000v
	mat.a[mat.n][mat.n] = 1; // 规定Un = 0v
	mat.Gauss();
	double flow = 0; // 电流
	for(int i=2; i<=mat.n; ++i)
		if(resistance[1][i] != 0)
			flow += (mat.a[1][mat.m]-mat.a[i][mat.m])/resistance[1][i];
	printf("%.2f\n",(mat.a[1][mat.m]-mat.a[mat.n][mat.m])/flow);
}

int main(){
	int T; scanf("%d",&T);
	for(int i=1; i<=T; ++i){
		printf("Case #%d: ",i);
		work(); // ppl or2
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值