【Hnoi2013】Bzoj3143 遊走

【Hnoi2013】Bzoj3143 遊走

Position:


List

Description

  • 一個無向連通圖,頂點從1編號到N,邊從1編號到M。
    小Z在該圖上進行隨機遊走,初始時小Z在1號頂點,每一步小Z以相等的概率隨機選 擇當前頂點的某條邊,沿着這條邊走到下一個頂點,獲得等於這條邊的編號的分數。當小Z 到達N號頂點時遊走結束,總分爲所有獲得的分數之和。
    現在,請你對這M條邊進行編號,使得小Z獲得的總分的期望值最小。。

Solution

整體理解: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\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章