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

    3143: [Hnoi2013]游走

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1026  Solved: 448
    [Submit][Status]

    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。
     
     
      这道题我又把题目看错了,我最开始看成了有向无环图,【目测世纪大水题】。。。
      当这种期望题出现环之后,就变的复杂很多,我们可以对于每一个点求出它的期望经过次数p[],则p[i]=segma(p[j]/d[j]),有一点还是有点不清楚,就是为什么p[1]在上述式子上必须恰好加1,就只好姑且先记住这样的结论吧。
      有了上述思路,就可以用高斯消元来做了。
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define MAXN 1000
    #define MAXV MAXN
    #define MAXE 500000
    #define abs(x) ((x)>0?(x):(-(x)))
    typedef long double real;
    struct Edge
    {
            int np;
            Edge *next;
    }E[MAXE],*V[MAXV];
    int tope=-1;
    void addedge(int x,int y)
    {
            E[++tope].next=V[x];
            E[tope].np=y;
            V[x]=&E[tope];
    }
    int deg[MAXN];
    int q[MAXN];
    real pp[MAXN];
    real a[MAXN][MAXN];
    int n,m;
    struct edge
    {
            int x,y;
            real p;
    }w[MAXE];
    bool cmp_p(edge e1,edge e2)
    {
            return e1.p>e2.p;
    }
    void pm()
    {
            for (int i=1;i<n;i++)
            {
                    for (int j=1;j<=n;j++)
                    {
                            printf("%.2Lf ",a[i][j]);
                    }
                    printf("
    ");
            }
            printf("
    ");
    }
    int main()
    {
            freopen("input.txt","r",stdin);
            int i,j,k,x,y,z;
            scanf("%d%d",&n,&m);
            for (i=0;i<m;i++)
            {
                    scanf("%d%d",&x,&y);
                    addedge(x,y);
                    addedge(y,x);
                    deg[x]++;deg[y]++;
                    w[i].x=x;w[i].y=y;
            }
            int now;
            Edge *ne;
            for (i=1;i<=n-1;i++)
            {
                    now=i;
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np!=n)
                                    a[now][ne->np]=1.0/deg[ne->np];
                    }
                    a[now][now]=-1;
                    a[now][n]=0;
            }
            a[1][n]=1;
            //pm();
            for (i=1;i<=n-1;i++)
            {
                    x=i;
                    for (j=i+1;j<=n-1;j++)
                    {
                            if (abs(a[j][i])>abs(a[x][i]))
                            {
                                    x=j;
                            }
                    }
                    if (x!=i)
                    {
                            for (j=i;j<=n;j++)
                            {
                                    swap(a[i][j],a[x][j]);
                            }
                    }
                    if (!a[i][i])continue;
                    for (j=i+1;j<=n-1;j++)
                    {
                            real t=a[j][i]/a[i][i];
                            for (k=i;k<=n;k++)
                            {
                                    a[j][k]-=t*a[i][k];
                            }
                    }
                    //pm();
            }
            pp[n]=1;
            for (i=n-1;i>=1;i--)
            {
                    for (j=i+1;j<=n;j++)
                    {
                            pp[i]-=pp[j]*a[i][j];
                    }
                    pp[i]/=a[i][i];
            }
            pp[n]=0;
    /*        for (i=1;i<=n;i++)
                    printf("%.2Lf ",pp[i]);
            printf("
    ");*/
            for (i=0;i<m;i++)
            {
                    w[i].p=pp[w[i].x]/deg[w[i].x] + pp[w[i].y]/deg[w[i].y];
            }
            sort(w,w+m,cmp_p);
            int head=-1,tail=-1;
            real ans=0;
            for (i=0;i<m;i++)
            {
                    ans+=(i+1)*w[i].p;
            }
            printf("%.3Lf",ans);
    }
    by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

    本博客已停用,新博客地址:http://mhy12345.xyz

  • 相关阅读:
    Linux设备模型 学习总结
    平衡二叉树
    数字在排序数组中出现的次数
    两个链表的第一个公共节点
    第一个只出现一次的字符
    丑数
    把数组排成最小的数
    剑指offer 连续子数组的最大和
    查找描述信息中包括robot的电影对应的分类名称以及电影数目,而且还需要该分类对应电影数量>=5部
    for each
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4116749.html
Copyright © 2011-2022 走看看