1. 程式人生 > >bzoj 3143: [Hnoi2013]遊走

bzoj 3143: [Hnoi2013]遊走

需要 wal names urn tdi long long iostream 初始 連通

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\n",ans);
  return 0;
}

bzoj 3143: [Hnoi2013]遊走