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





学生社团系统-学生社团“一站式”运营管理平台-学生社团管理系统-基于SSM的学生社团管理系统-springboot学生社团管理系统.zip-Java学生社团管理系统开发实战-源码 更多学生社团系统: SpringBoot+Vue学生社团“一站式”运营管理平台源码(活动管理+成员考核+经费审批) Java学生社团管理系统开发实战:SSM升级SpringBoot(招新报名+场地预约+数据看板) 基于SpringSecurity的社团管理APP(移动端签到+权限分级+消息推送) 企业级社团数字化平台解决方案(SpringBoot+Redis缓存+Elasticsearch活动搜索) 微信小程序社团服务系统开发(活动直播+社团文化墙+成员互动社区) SpringBoot社团核心源码(多角色支持+工作流引擎+API接口开放) AI赋能社团管理:智能匹配兴趣标签+活动热度预测+成员贡献度分析(附代码) 响应式社团管理平台开发(PC/移动端适配+暗黑模式+无障碍访问) 完整学生社团系统源码下载(SpringBoot3+Vue3+MySQL8+Docker部署) 高校垂直领域社团平台:百团大战系统+社团星级评定+跨校活动联盟 适用对象:本代码学习资料适用于计算机、电子信息工程、数学等专业正在做毕设的学生,需要项目实战练习的学习者,也适用于课程设计、期末大作业。 技术栈:前端是vue,后端是springboot,项目代码都经过严格调试,代码没有任何bug! 核心管理:社团注册、成员管理、权限分级 活动运营:活动发布、报名签到、场地预约 资源服务:经费申请、物资管理、文档共享 数据分析:成员活跃度、活动效果评估、社团影响力排名
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值