题目
题目概要
给你一个电路图,求
1
1
1 号节点到
n
n
n 号节点的总电阻是多少。
数据范围与约定
数据组数
T
≤
100
,
1
<
n
≤
50
,
0
<
T\le 100,1<n\le 50,0<
T≤100,1<n≤50,0< 边的数量
m
≤
2000
,
1
≤
m\le 2000,1\le
m≤2000,1≤ 电阻阻值
R
≤
1
0
4
R\le 10^4
R≤104 。图是联通的简单图。
思路
众所周知,电压来源于电势差。
所以假设每个节点的电势即可。然后利用流入电流 = = = 流出电流建立方程即可。
可以规定 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;
}