E42 概率DP 求期望 高斯消元

视频链接:https://www.bilibili.com/video/BV1kP411m7xv/

Luogu P3232 [HNOI2013]游走

时间:O(n^3+mlogm)

#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=510,M=125010;
const double eps=1e-6;
int n,m;
int h[N],to[M<<1],ne[M<<1],tot;
int d[N],s[M],t[M]; //点的度,边的起点、终点
double a[N][N],g[M],ans;

void add(int u,int v){
  to[++tot]=v;ne[tot]=h[u];h[u]=tot;
}
void gauss(){
  for(int i=1; i<n; ++i){    //第i主元
    for(int k=i; k<n; ++k)   //换非0行
      if(fabs(a[k][i])>eps)
        {swap(a[k],a[i]); break;}
    
    for(int k=1; k<n; ++k)  //对角化
      if(k!=i) for(int j=n; j>=i; --j) 
        a[k][j]-=a[k][i]/a[i][i]*a[i][j];
  }
  for(int i=1;i<n;++i) a[i][n]/=a[i][i]; //除以主元
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=1;i<=m;i++){
    scanf("%d%d",&s[i],&t[i]);
    add(s[i],t[i]); add(t[i],s[i]);
    d[s[i]]++; d[t[i]]++;
  }
  
  for(int u=1;u<n;u++){         //构造增广矩阵
    for(int i=h[u];i;i=ne[i]){
      int v=to[i];
      if(v!=n)a[u][v]=-1.0/d[v];//从v走到u的概率
    }
    a[u][u]=1;                  //fu移项后的系数
  }
  a[1][n]=1;                    //f1的常数项
  
  gauss();              //点的期望次数
  for(int i=1;i<=m;i++) //边的期望次数
    g[i]=a[s[i]][n]/d[s[i]]+a[t[i]][n]/d[t[i]];
    
  sort(g+1,g+m+1);
  for(int i=1;i<=m;i++) 
    ans+=g[i]*(m-i+1);  //次数多,编号小(贪心)
  printf("%.3lf\n",ans);
}

 

练习:

CF24D Broken robot

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=1010;
double a[N][N],f[N];
int n,m,st,ed;

void solve(){
  for(int k=n-1; k>=st; k--){
    memset(a,0,sizeof a);
    for(int i=1; i<=m; i++){
      if(i==1){
        a[i][i]=2;
        a[i][i+1]=-1;
        a[i][m+1]=3+f[i];
        continue;
      } 
      else if(i==m){
        a[i][i]=2;
        a[i][i-1]=-1;
        a[i][m+1]=3+f[i];
        continue;
      }
      a[i][i]=3;
      a[i][i+1]=-1;
      a[i][i-1]=-1;
      a[i][m+1]=4+f[i];
    }
    
    for(int i=1; i<m; i++){
      double p=a[i+1][i]/a[i][i];
      a[i+1][i]=0;
      a[i+1][i+1]-=a[i][i+1]*p;
      a[i+1][m+1]-=a[i][m+1]*p;
    }
    f[m]=a[m][m+1]/a[m][m];
    for(int i=m-1; i>=1; i--)
      f[i]=(a[i][m+1]-f[i+1]*a[i][i+1])/a[i][i];
  }
}
int main(){
  scanf("%d %d",&n,&m);
  scanf("%d %d",&st,&ed);
  if(m==1){
    printf("%.10f\n",2.0*(n-st)); return 0;
  }
  solve();
  printf("%.10f\n",f[ed]);
}

Luogu P4457 [BJOI2018]治疗之雨

HDU4418 Time Travel

 

posted @ 2023-04-20 23:24  董晓  阅读(356)  评论(0编辑  收藏  举报