bzoj2419 电阻 [高斯消元]

in 题目 with 0 comment

Description

你突破了无数艰难险阻,终于解决了上面那道题,众神犇瞬间就震惊了。他们发现居然有人可以把那种非人类做的题目做出来。他们一致同意,最后这道题不能再出数学题了。考虑到两位小盆友的状态,他们决定考考你的初中物理水平。 一个电路板,有 N 个接点,M 个电阻。电阻两端都在接点上,两位小盆友很聪明,他们拿出了一个欧姆表,瞬间就虐爆了…不过你也不甘落后,你肯定不会用这种投机取巧、误差巨大的方法,于是你看向了你的电脑。


Input

多组数据,输入直到文件结束
每组数据第一行两个整数N,M
接下来 M 行,每行三个非负整数 X,Y,R,表示电阻连接的两
接点和阻值。


Output

每组数据输出一行,一个实数,四舍五入到小数点后两位


Sample Input

2 1
1 2 1


Sample Output

1.00


Hint

$ 0< N\le 200$
$ 0< M\le 50000$


Solution

这题BZOJ居然没给数据范围!狂WA了若干次都没发现原因,坑得要命TAT

根据我们的物理知识$ I_{ab}=\frac{U}{R}=\frac{\phi(b)-\phi(a)}{R_{ab}} $,我们又知道对于(除起始点外
)任意一个点流入的电流等于流出的电流
,于是我们可以令第一个点流出电流$I_1=1$,则最后一点流入电流$I_N=1$,再令第N个点电势$\phi(N)=0$,求出的$\phi(1)$即为要求的等效电阻.第一个点的值为-1,最后一个点的值为1


Code

#include<bits/stdc++.h>
#define maxm 100010
#define maxn 1010
#define eps 1e-6
// #define DEBUG
using namespace std;
int n,m,num_edge;
double a[maxn][maxn];
int now[maxm],pre[maxm],to[maxm],deg[maxm],w[maxm];

int dcmp(double x)
{
  if(abs(x)<=eps) return 0;
  else return x>0?1:-1;
}

void add_edge(int u,int v,int wi)
{
  pre[++num_edge]=now[u];
  w[num_edge]=wi;
  now[u]=num_edge;
  to[num_edge]=v;
  deg[v]++;
}

inline int read()
{
  char ch;
  int sign=1,read=0;
  do
    ch=getchar();
  while((ch<'0'||ch>'9')&&ch!='-');
  if(ch=='-') sign=-1,ch=getchar();
  while(ch>='0' && ch<='9')
  {
    read=read*10+ch-'0';
    ch=getchar();
  }
  return sign*read;
}

void init()
{
  num_edge=0;
  memset(a,0,sizeof(a));
  for(int i=1;i<=max(n,m);++i)
    deg[i]=pre[i]=now[i]=to[i]=w[i]=0;
  for(int i=1,x,y,r;i<=m;++i)
    x=read(),y=read(),r=read(),add_edge(x,y,r),add_edge(y,x,r);
  for(int i=1;i<=n;++i)
    for(int x=now[i];x;x=pre[x])
    {
      a[i][to[x]]+=1.0/w[x];
      a[i][i]-=1.0/w[x];
    }
  a[1][n+1]=-1.0;
  a[n][n+1]=1.0;
  a[n][n]-=1.0;
}

void gauss()
{
  for(int i=1;i<=n;++i)
  {
    if(!dcmp(a[i][i]))
    {
      int k=i;
      while(!dcmp(a[k][k])) k++;
      swap(a[i],a[k]);
    }
    for(int j=i+1;j<=n;++j)
    {
      for(int k=i+1;k<=n+1;++k)
        a[j][k]-=a[i][k]*(a[j][i]/a[i][i]);
      a[j][i]=0;
    }
  }
  for(int i=n;i>1;--i)
    for(int j=1;j<i;++j)
    {
      a[j][n+1]-=a[i][n+1]*(a[j][i]/a[i][i]);
      a[j][i]=0;
    }
  printf("%.2lf\n",a[1][n+1]/a[1][1]+eps);
}

int main()
{
#ifdef DEBUG
  freopen("resistor.in","r",stdin);
/*#else
  freopen("resistor.in","r",stdin);
  freopen("resistor.out","w",stdout);*/
#endif
  while(scanf("%d%d",&n,&m)==2)
  {
    init();
#ifdef DEBUG
    for(int i=1;i<=n;++i)
    {
      cerr<<"i="<<i<<" -->";
      for(int p=now[i];p;p=pre[p])
        cerr<<to[p]<<" ";
      cerr<<";"<<endl;
    }
    for(int i=1;i<=n;++i){
      for(int j=1;j<=n+1;++j)
        printf("%.3lf ",a[i][j]);
      cout<<endl;}
#endif
    gauss();
  }
  return 0;
}

扫描二维码,在手机上阅读!
Responses