[HNOI2013]游走

题面在这里

题意

从1号点开始等概率选择路径并加上边权,直到到达n号点结束,要求将m条边赋权值1-m使得期望最小

sol

上文 zsy ycb orz
简单的贪心:求出每条边的期望经过次数,sort之后对于第x小的边赋权值为x即可
于是答案转换为求边的期望经过次数
思想转换:直接求边不好求,考虑求出每个点的期望经过次数;
那么我们同样设\(f[u]\)表示经过点u的期望次数,则有

\[f[u]=\sum_{v\in e(u,v)} {\frac{f[v]}{d[v]}} \]

移项既有$$f[u]-\sum_{v\in e(u,v)} {\frac{f[v]}{d[v]}}=0$$
使用高斯消元直接求解,发现全都是0(WA飞了)。

需要特判:因为我们从1号点开始,所以

\[f[1]-\sum_{v\in e(1,v)} {\frac{f[v]}{d[v]}}=1 \]

n号点不能转移,因此\(f[n]=0\)

代码

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
const int mod=1e9+7;
const int N=510;
const int M=N*N*2;
const double eps=1e-10;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
il ll read(){
    RG ll data=0,w=1;RG char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
    return data*w;
}

int n,m,head[N],nxt[M],to[M],cnt,d[N],tot;
dd ans;
il void add(int u,int v){
    to[++cnt]=v;
    nxt[cnt]=head[u];
    head[u]=cnt;
    d[v]++;
}

struct edge{int u,v;dd w;}e[M];
bool cmp_w(edge a,edge b){return a.w<b.w;}

dd S[N][N];
il bool gauss(){//高斯消元
    for(RG int i=1;i<=n;i++){
        for(RG int j=i;j<=n;j++)
            if(abs(S[j][i])>eps){swap(S[i],S[j]);break;}
        if(abs(S[i][i])<=eps)return 0;
        for(RG int j=i+1;j<=n;j++)
            for(RG int k=n+1;k>=i;k--)
                S[j][k]-=S[i][k]*S[j][i]/S[i][i];
    }

    for(RG int i=n;i;i--){
        for(RG int j=i+1;j<=n;j++)
            S[i][n+1]-=S[i][j]*S[j][n+1];
        S[i][n+1]/=S[i][i];
    }
    return 1;
}

int main()
{
    n=read();m=read();
    for(RG int i=1,u,v;i<=m;i++){
        u=read();v=read();
        add(u,v);add(v,u);
        e[++tot]=(edge){u,v,0};
    }

    S[1][n+1]+=1.0;
    for(RG int u=1;u<n;u++)
        for(RG int i=head[u];i;i=nxt[i]){
            RG int v=to[i];
            S[u][v]-=1.0/d[v];
        }
    for(RG int i=1;i<=n;i++)S[i][i]+=1.0;
    //求出系数
    gauss();
    
    for(RG int i=1;i<=tot;i++)
        e[i].w=S[e[i].u][n+1]/d[e[i].u]+S[e[i].v][n+1]/d[e[i].v];
    sort(e+1,e+tot+1,cmp_w);
    for(RG int i=1;i<=tot;i++)
        ans+=(tot-i+1)*e[i].w;
    //排序后贪心
    printf("%.3lf\n",ans);
    
    return 0;
}

posted @ 2018-02-02 10:18  cjfdf  阅读(156)  评论(0编辑  收藏  举报