【Hnoi2013】Bzoj3143 游走

Position:


List

Description

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

xSolution

整体理解:a[i][j]表示从i号点走到j号点概率次数。由于走到n不走了,故a[n][i]=0。i→i为-1。初始值a[1][n+1]=-1,代表从1号点出发次数为1。然后Gauss消元求出每个点的期望经过次数,那么对于一条边ei,它的期望经过次数就为e[i]=a[u[i]][n+1]/d[u[i]]+a[v[i]][n+1]/d[v[i]],将边的期望经过次数排序,根据贪心思想,次数多的边赋小值答案更优,ans=e[i]*(m-i+1)。
模板:高斯消元还是第一次写,O(n^3)。
深入理解:每一个未知数代表从这个点到达的次数,用它/出度即为对与它相邻边贡献。考虑一个点,到达次数f[i]=∑f[from]/d[from],移到左边-f[i]+∑f[from]/d[from]=0,特殊的,对于第一个点次数右边等于-1,即开始从这里出发,次数为1。对于第n个点,有点奇怪,到这个点的次数为0,这样是为了满足条件到了n号点,就不会出去了,不会对其它点的值造成影响,而最后也不是要求每个点到达次数期望。而是每条边的次数,而n也不会对与其相连的边的期望次数造成影响,所以Accept。

Code

// <hang.cpp> - 08/01/16 15:30:38
// This file is made by YJinpeng,created by XuYike's black technology automatically.
// Copyright (C) 2016 ChangJun High School, Inc.
// I don't know what this program is.

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define MOD 1000000007
#define EPS 1e-10 
#define INF 1e9
using namespace std;
typedef long long LL;
const int MAXN=510;
const int MAXM=100010;
inline int max(int &x,int &y) {return x>y?x:y;}
inline int min(int &x,int &y) {return x<y?x:y;}
inline int getint() {
    register int w=0,q=0;register char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')q=1,ch=getchar();
    while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();
    return q?-w:w;
}
double ans;
int n,m,d[MAXN],u[MAXN*MAXN],v[MAXN*MAXN];
double a[MAXN][MAXN],e[MAXN*MAXN];
void Gauss(){
    for(int i=1;i<=n;i++){
        for(int k=i+1;k<=n;k++)if(fabs(a[k][i])>fabs(a[i][i]))swap(a[k],a[i]);
        for(int j=n+1;j>=i;j--)a[i][j]/=a[i][i];
        for(int k=i+1;k<=n;k++)
            for(int j=n+1;j>=i;j--)a[k][j]-=a[k][i]*a[i][j];
    }
    for(int i=n;i;i--)
        for(int k=i-1;k;k--)a[k][n+1]-=a[k][i]*a[i][n+1];
}
int main()
{
    freopen("hang.in","r",stdin);
    freopen("hang.out","w",stdout);
    n=getint();m=getint();
    for(int i=1;i<=m;i++){
        u[i]=getint();v[i]=getint();
        d[u[i]]++;d[v[i]]++;
    }
    for(int i=1;i<=m;i++){
        a[u[i]][v[i]]+=1.0/d[v[i]];
        a[v[i]][u[i]]+=1.0/d[u[i]];
    }
    for(int i=1;i<=n;i++)a[n][i]=0,a[i][i]=-1;
    a[1][n+1]=-1;ans=0;Gauss();
    for(int i=1;i<=m;i++)e[i]=a[u[i]][n+1]/d[u[i]]+a[v[i]][n+1]/d[v[i]];
    sort(e+1,e+1+m);
    for(int i=1;i<=m;i++)ans+=e[i]*(m-i+1);
    printf("%.3f
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/YJinpeng/p/5907208.html