zoukankan      html  css  js  c++  java
  • bzoj 3143: [Hnoi2013]游走

    Description

    一个无向连通图,顶点从1编号到N,边从1编号到M。 
    小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。 
    现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。

    Input

    第一行是正整数N和M,分别表示该图的顶点数 和边数,接下来M行每行是整数u,v(1≤u,v≤N),表示顶点u与顶点v之间存在一条边。 输入保证30%的数据满足N≤10,100%的数据满足2≤N≤500且是一个无向简单连通图。

    Output

    仅包含一个实数,表示最小的期望值,保留3位小数。

    Sample Input

    3 3
    2 3
    1 2
    1 3

    Sample Output

    3.333

    HINT

    边(1,2)编号为1,边(1,3)编号2,边(2,3)编号为3。

    Source

    实在是闲的没事做才把这个题做掉。。。

    首先我们可以需要计算每条边被经过的概率,因为要总期望最小,那么要让经过概率高的边的权值小,sort一遍即可。。。

    如何求一条边被经过的概率呢,设边(x,y),经过x的概率是g[x],经过y的概率是g[y],x的度数为du[x],y的度数为du[y]。。。

    那么答案显然等于g[x]/du[x]+g[y]/du[x];

    然后我们相当于是要求经过每个点的概率(因为到了n就停止,所以我们要求经过1-n-1的点的概率,经过n的概率为0)

    那么显然g[x]=∑g[y]/du[y]。。。

    然后我们发现这是一个转移有环的dp,我们可以通过高斯消元来解决,经过1的概率为1。。

    然后得出解,那么再算出每条边经过的概率,然后sort一遍出解。。。

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=3000;
    int n,m,head[N],nxt[300050],to[300050],cnt,du[N];
    double a[N][N],v[300050];
    void gauss() {
      for(int i=1;i<=n;i++) {
        int t=i;
        while(!a[t][i]) t++;
        if(i!=t) swap(a[t],a[i]);
        double k=a[i][i];
        for(int j=i;j<=n+1;j++) a[i][j]/=k;
        for(int j=1;j<=n;j++)
          if(j!=i&&a[j][i]) {
    	k=a[j][i];
    	for(int p=i;p<=n+1;p++) a[j][p]-=k*a[i][p];
          }
      }
    }
    void lnk(int x,int y){
      du[x]++;du[y]++;
      to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
      to[++cnt]=x,nxt[cnt]=head[y],head[y]=cnt;
    }
    struct data{
      int x,y;
    }e[300050];
    bool cmp(double a,double b){return a>b;}
    int main(){
      freopen("walk.in","r",stdin);
      freopen("walk.out","w",stdout);
      scanf("%d%d",&n,&m);
      for(int i=1;i<=m;i++){scanf("%d%d",&e[i].x,&e[i].y);lnk(e[i].x,e[i].y);}
      n--;
      for(int x=1;x<=n;x++){
        for(int i=head[x];i;i=nxt[i]){
          int y=to[i];if(y!=n+1) a[x][y]=1.0/du[y];
        }
        a[x][x]=-1.0;
      }
      a[1][n+1]=-1.0;gauss();
      for(int i=1;i<=m;i++) v[i]=a[e[i].x][n+1]/du[e[i].x]+a[e[i].y][n+1]/du[e[i].y];
      sort(v+1,v+1+m,cmp);double ans=0;for(int i=1;i<=m;i++) ans+=v[i]*i;printf("%.3f
    ",ans);
      return 0;
    }
  • 相关阅读:
    python3----练习题(斐波那契)
    python3----运算符
    python3----函数、匿名函数
    python3----生成器generator(yield)
    Python捕获异常
    OS模块
    发送邮件
    IO文件读写
    Unittest框架概念
    生成报告
  • 原文地址:https://www.cnblogs.com/qt666/p/7376348.html
Copyright © 2011-2022 走看看