真正的危机不是机器人像人一样思考,而是人像机器一样思考。 ——凉宫春日的忧郁

[补档][Hnoi2013]游走

[Hnoi2013]游走

题目

一个无向连通图,顶点从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

OUTPUT

3.333

解题报告

这东西显然是个概率与期望(题目写的那么清楚啊喂),好吧,是一个很裸的概率与期望。
题目要求总分最小,且编号从1到m,那么显然,我们需要求一下每条边被经过的期望,期望越大,编号越小。
首先自然能删除终点的所有出边(终点是不能出来的),然后,对于每一条边,设两端端点为u,v,我们可以从u走到v,也可以从v走到u,从u走到v的期望次数等于

经过点u的次数/u的度

问题自然就转化成求每个点的期望经过次数,对于起点来说,一开始一定会经过一次,在之后也可能被经过。

f[1]=1+sigma(f[j]/degree[j],j和1有边相连)

f[i]=sigma(f[j]/degree[j],i与j有边相连)

我们得到了n变量n方程的方程组,然后高斯消元乱抡= =
稍微处理下就可以得到经过每个点的期望,那么每条边的期望即为两端点期望之和(注意:对终点一定要特殊处理啊啊啊),对每条边按期望排序,随便一乘,一加,就可以AC了。
  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 using namespace std;
  6 inline int read(){
  7     int sum(0);
  8     char ch(getchar());
  9     for(;ch<'0'||ch>'9';ch=getchar());
 10     for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar());
 11     return sum;
 12 }
 13 struct edge{
 14     int s,e,n;
 15 }ed[250001];
 16 int pre[501],tot;
 17 inline void insert(int s,int e){
 18     ed[++tot].s=s;
 19     ed[tot].e=e;
 20     ed[tot].n=pre[s];
 21     pre[s]=tot;
 22 }
 23 int du[501];
 24 int n,m;
 25 double a[501][501],b[501],ans[501];
 26 inline double jdz(double x){
 27     return x>=0?x:-x;
 28 }
 29 inline void swp(double &a,double &b){
 30     double c(a);
 31     a=b;
 32     b=c;
 33 }
 34 inline void gauss(){
 35     int num,cnt(1);
 36     for(int i=1;i<n;i++,cnt++){
 37         num=i;
 38         for(int j=i+1;j<=n;j++)
 39             if(jdz(a[num][i])<jdz(a[j][i]))
 40                 num=j;
 41         if(num!=i){
 42             for(int j=1;j<=n;j++)
 43                 swp(a[num][j],a[cnt][j]);
 44             swp(b[num],b[cnt]);
 45         }
 46         if(!a[cnt][i]){
 47             cnt--;
 48             continue;
 49         }
 50         for(int j=cnt+1;j<=n;j++){
 51             double t(a[j][i]/a[cnt][i]);
 52             for(int k=i;k<=n;k++)
 53                 a[j][k]-=t*a[i][k];
 54             b[j]-=t*b[i];
 55         }
 56     }
 57     for(int i=n;i>0;i--){
 58         for(int j=n;j>i;j--)
 59             b[i]-=a[i][j]*ans[j];
 60         ans[i]=b[i]/a[i][i];
 61     }
 62 }
 63 double f[250001];
 64 bool g[501][501];
 65 inline int gg(){
 66 //  freopen("walk.in","r",stdin);
 67 //  freopen("walk.out","w",stdout);
 68     n=read(),m=read();
 69     for(int i=1;i<=m;i++){
 70         int x(read()),y(read());
 71         insert(x,y);
 72         g[x][y]=g[y][x]=1;
 73         du[x]++,du[y]++;
 74     }
 75     du[n]=0;
 76     for(int i=1;i<=n;i++){
 77         if(i==1)
 78             b[i]=1;
 79         else
 80             b[i]=0;
 81         for(int j=1;j<=n;j++){
 82             if(i==j){
 83                 a[i][j]=1;
 84                 continue;
 85             }
 86             if(j==n){
 87                 a[i][j]=0;
 88                 continue;
 89             }
 90             if(g[i][j])
 91                 a[i][j]=-1.0/(double)du[j];
 92         }
 93     }
 94     gauss();
 95     for(int i=1;i<n;i++)
 96         ans[i]/=du[i];
 97     ans[n]=0;
 98     for(int i=1;i<=tot;i++){
 99         int s(ed[i].s),e(ed[i].e);
100         f[i]=ans[s]+ans[e];
101     }
102     int cnt(tot);
103     sort(f+1,f+tot+1);
104     double an(0);
105     for(int i=1;i<=tot;i++)
106         an+=i*f[cnt--];
107     printf("%.3lf",an);
108     return 0;
109 }
110 int k(gg());
111 int main(){;}
View Code
ps:COGS rk1代码奉上,虽然榜貌似被两个神奇的(hhh)刷成(hhh)了,但是还是没有什么影响。。。
posted @ 2017-08-02 20:43  Hzoi_Mafia  阅读(290)  评论(0编辑  收藏  举报
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。 ——死神