HDU 5006 Resistance 缩点 + 高斯消元

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.

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.

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();
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值