Resistance
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 316 Accepted Submission(s): 88
Problem Description
Recently DRD got a number of wires. Some of the wires have the resistance 1 ohm while the others have the resistance 0 ohm. Each wire has probability 50% to be 0 ohm or 1 ohm.
Now ATM gets a circuit board. There are N points in the circuit board. DRD wants to connect these points using his wires. He chooses a wire randomly and chooses two points in the board randomly. Then he will connect the two points using the wire he chooses. DRD will use M wires. Note that it's possible that there exist two points which are not connected by wires.
ATM is interested in the equivalent resistance between the point S and point T. Since they lack of instruments, they want you to calculate the answer.
Now ATM gets a circuit board. There are N points in the circuit board. DRD wants to connect these points using his wires. He chooses a wire randomly and chooses two points in the board randomly. Then he will connect the two points using the wire he chooses. DRD will use M wires. Note that it's possible that there exist two points which are not connected by wires.
ATM is interested in the equivalent resistance between the point S and point T. Since they lack of instruments, they want you to calculate the answer.
Input
The first line contains an integer T, denoting the number of the test cases.
For each test case: The first line contains 4 integers: N, M, S, and T. For each of the next M lines, it contains 3 integers: u, v, and c, representing that DRD uses a wire, whose resistance is c, to connect the point u and v. It's guaranteed that 1 <= N <= 10000 and M = 4*N. 1 <= u, v <= N. c is randomly chosen from {0, 1} and u and v are randomly chosen from {1, 2, ..., N}. Note that u can equal v.
For each test case: The first line contains 4 integers: N, M, S, and T. For each of the next M lines, it contains 3 integers: u, v, and c, representing that DRD uses a wire, whose resistance is c, to connect the point u and v. It's guaranteed that 1 <= N <= 10000 and M = 4*N. 1 <= u, v <= N. c is randomly chosen from {0, 1} and u and v are randomly chosen from {1, 2, ..., N}. Note that u can equal v.
Output
For each test case, output a real number. There must be exactly 6 digits after the decimal point. If S and T are not connected by wires, output "inf" (without quotes) instead.
Sample Input
2 10 40 6 1 9 4 1 7 3 1 10 1 0 5 2 0 6 7 1 7 3 1 3 5 1 3 6 1 8 10 0 8 3 0 7 3 1 3 9 1 2 8 1 10 5 0 10 2 1 10 9 1 9 1 0 7 5 1 10 2 0 8 1 0 2 8 0 10 2 0 1 5 0 5 4 0 7 4 1 8 5 1 4 3 1 6 1 1 5 10 0 3 9 1 5 1 0 9 2 1 3 4 1 5 8 0 3 5 1 3 4 1 2 7 0 4 4 0 1 8 0 10 10 0 10 40 2 1 5 6 1 8 10 1 3 8 1 8 5 0 6 4 1 9 9 1 3 6 1 2 4 1 9 8 0 9 3 0 7 7 1 8 6 1 10 4 1 1 3 0 2 8 1 9 8 0 8 1 1 6 4 0 3 4 0 1 4 0 1 10 0 9 10 0 6 1 1 3 1 1 5 4 0 1 2 1 7 2 1 10 9 0 6 1 0 10 3 1 8 6 1 1 4 0 1 1 0 4 3 0 1 8 0 7 10 1 10 6 0 4 5 0 2 2 0 4 2 1
Sample Output
0.333333 0.222222
Source
题意:随机的给出一个电路图,电阻只为0或者1,求S到T的等效电阻。
思路:首先图是随机的,那么我们能够把能通过电阻为0的的边相通的点合并到一起,因为他们的电势都是一样的,然后我们设出每个点的电势Ui, 由于电阻都是1,所以某条边的电流恰好等于电势差Uj-Ui . 由于对于每个点进来的电流等于出去的电流,那么有sigma (Ui - Uj) = 0 (枚举i的相邻节点j) , 为了方便求结果,我们设S出来的电流是1.0,那么进去T的电流就是1.0, 再随意设一个点的电势为0,那么就可以求出每个点的电势了,那么最后S到T的电压就是电势差,电阻就是电势差 / 1.0 . 上面对于每个点都有一个方程,所以我们能用高斯消元搞一下。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <algorithm>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<(int)(b);++i)
#define rrep(i,b,a) for(int i=(b);i>=(int)(a);--i)
#define eps 1e-8
#define clr(a,x) memset(a,x,sizeof(a))
#define LL long long
const int maxn = 10000+5;
int p[maxn];
int find(int x)
{
if (x == p[x]) return x;
return p[x] = find(p[x]);
}
int u[maxn*4],v[maxn*4],c[maxn*4];
int id[maxn],tot;
double A[500][500];
int N,M,S,T;
void input()
{
scanf("%d%d%d%d",&N,&M,&S,&T);
rep(i,0,M) scanf("%d%d%d",u+i,v+i,c+i);
}
void gauss(int n)
{
int i , j , k , r;
for(i=0; i < n; ++i) {
r = i;
for(j = i+1; j <= n; ++j)
if (fabs(A[j][i]) > fabs(A[r][i])) r = j;
if (r != i) for(j = 0; j <= n; ++j) swap(A[r][j],A[i][j]);
for(j = i+1; j <= n; ++j) A[i][j] /= A[i][i];
A[i][i] = 1.0;
for(k = 0; k < n; ++k) {
if (fabs(A[k][i]) < eps || i == k) continue;
double f = A[k][i];
for(j = 0; j <= n; ++j) A[k][j] -= f * A[i][j];
}
}
}
void solve()
{
rep(i,1,N+1) p[i] = i;
rep(i,0,M) if (c[i] == 0)
p[find(u[i])] = find(p[v[i]]); //合并电势一样的点
//
if (find(S) == find(T)) {
printf("0.000000\n");
return;
}
//重新标记
tot = 0;
rep(i,1,N+1)
if (find(i) == i) id[i] = tot++;
rep(i,1,N+1)
id[i] = id[find(i)];
//检查连S-T通性
rep(i,0,tot) p[i] = i;
rep(i,0,M) p[find(u[i])] = find(v[i]);
if (find(S) != find(T)) {
//不连通
puts("inf");
return;
}
clr(A,0);
//构建方程组
rep(i,0,M) {
if (id[u[i]] == id[v[i]]) continue;
int x = id[u[i]] , y = id[v[i]];
++A[x][x]; --A[x][y];
++A[y][y]; --A[y][x];
}
S = id[S]; T = id[T];
A[S][tot] = 1.0; A[T][tot] = -1.0;
A[tot-1][S]++;
gauss(tot);
printf("%.6lf\n",-A[T][tot] + A[S][tot] + eps);
}
int main()
{
int T; cin >> T;
while (T--) {
input();
solve();
}
}