码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ 3143][Hnoi2013]游走(高斯消元+期望)

时间:2017-05-07 00:06:49      阅读:249      评论:0      收藏:0      [点我收藏+]

标签:struct   贪心   ret   next   sum   1.0   can   name   set   

Description

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

Solution

对于点u(u≠1):到达u的概率 f[u]=∑f[v]/d[v] (Edges(u,v))

而f[1]=∑f[v]/d[v]+1 (Edges(1,v))

高斯消元可以求出所有点的概率

对于每条边 到达边i的概率 p[i]=f[u]/d[u]+f[v]/d[v]

贪心的编号然后求出期望就好了

好像BZOJ上的数据会比较水,洛谷数据…卡精度

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define eps 1e-7
using namespace std;
int n,m,head[505],cnt=0,d[505];
double a[505][505],f[505],p[250005];
struct Node
{
    int next,from,to;
}Edges[500005];
void addedge(int u,int v)
{
    Edges[++cnt].next=head[u];
    head[u]=cnt;
    Edges[cnt].from=u;
    Edges[cnt].to=v;
}
void Gauss()
{
    for(int i=1;i<=n;i++)
    {
        int maxline=i;
        for(int j=i+1;j<=n;j++)
        if(a[j][i]>a[maxline][i])maxline=j;
        if(maxline!=i)
        for(int j=i;j<=n+1;j++)
        swap(a[maxline][j],a[i][j]);
        for(int j=i+1;j<=n;j++)
        {
            if(fabs(a[j][i])<eps)continue;
            double t=a[j][i]/a[i][i];
            for(int k=i;k<=n+1;k++)
            a[j][k]-=t*a[i][k];
        }
    }
    for(int i=n;i>0;i--)
    {
        for(int j=n;j>i;j--)
        a[i][n+1]-=f[j]*a[i][j];
        f[i]=a[i][n+1]/a[i][i];
    }
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
        d[u]++,d[v]++;
    }
    for(int i=1;i<n;i++)
    {
        a[i][i]=1;
        for(int j=head[i];~j;j=Edges[j].next)
        a[i][Edges[j].to]=-1.0/d[Edges[j].to];
    }
    a[1][n+1]=1,a[n][n]=1;
    Gauss();
    for(int i=1;i<=cnt;i+=2)
    {
        int u=Edges[i].from,v=Edges[i].to;
        p[(i+1)>>1]+=(double)f[u]/d[u];
        p[(i+1)>>1]+=(double)f[v]/d[v];
    }
    sort(p+1,p+1+m);
    double ans=0;
    for(int i=1;i<=m;i++)
    ans+=p[i]*(m-i+1);
    printf("%.3lf\n",ans);
    return 0;
} 

 

被卡精度)

 

[BZOJ 3143][Hnoi2013]游走(高斯消元+期望)

标签:struct   贪心   ret   next   sum   1.0   can   name   set   

原文地址:http://www.cnblogs.com/Zars19/p/6819037.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!