BZOJ 3143 HNOI2013 游走 高斯消元 期望

这道题是我第一次使用高斯消元解决期望类的问题,首发A了,感觉爽爽的....

不过笔者在做完后发现了一些问题,在原文的后面进行了说明。

 

中文题目,就不翻大意了,直接给原题:

  一个无向连通图,顶点从1编号到N,边从1编号到M。 

  小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。 

  现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。

  输出最小的总分期望值。

 

Solution:

  这题贪心很明显,哪条边走过次数的期望最大,它就应该获得最小的编号。

  所以假设我们已经求出了每条边走过的期望,我们就可以给它们并编上号了。

  怎么算出每条边走过的期望呢?

  每条边连接着两个点u,v,很明显的,当我们经过这条边,一定是从两个点中的某一个进入。

  所以走过边l的期望=走过u点的期望次数*从u点走到l上的概率+走过v点的期望次数*从v点走到l上的概率 (其中从i点走到它连接边的概率为1/d[i],d[i]为i的度数)

  即:E[l]=e[u]/d[u]+e[v]/d[v]

  可是我们只知道e[n]=0。但我们还知道这些点之间哪些是连通的,从而可以得出它们之间的关系:

  

  我们就可以利用这些点之间的关系建立起方程组,从而使用高斯消元求解。

  别忘了,点求解完还要带回到每条边上去哦....

  

  附Bzoj上的AC代码(codevs上过不了...我也不知道为什么...)

  

  1 /*
  2   Problem : Bzoj 3143 概率 & 高斯消元 
  3   Author : Robert Yuan
  4   Memory : 15604 kb
  5   Time : 628 MS    
  6   Result : Accept
  7 */
  8 #include <cmath> 
  9 #include <cstdio>
 10 #include <cstring>
 11 #include <cstdlib>
 12 #include <algorithm>
 13 
 14 using namespace std;
 15 
 16 #define maxn 520
 17 
 18 struct Node{
 19     int data,next;
 20 }node[maxn*maxn<<1];
 21 
 22 struct Edge{
 23     int u,v;
 24     double w;
 25 }edge[maxn*maxn<<1];
 26 
 27 #define now node[point].data
 28 #define then node[point].next
 29 
 30 int n,m,cnt;
 31 int head[maxn],deg[maxn];
 32 const double eps=1e-6;
 33 double w[maxn][maxn],rec_x[maxn],ans;
 34 
 35 bool cmp(const Edge A,const Edge B){
 36     return A.w>B.w;
 37 }
 38 
 39 inline int in(){
 40     int x=0;char ch=getchar();
 41     while(ch>'9' || ch<'0') ch=getchar();
 42     while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
 43     return x;
 44 }
 45 
 46 void add(int u,int v){
 47     node[++cnt].data=v;node[cnt].next=head[u];deg[u]++;head[u]=cnt;
 48     node[++cnt].data=u;node[cnt].next=head[v];deg[v]++;head[v]=cnt;
 49 }
 50 
 51 void prework(){
 52     n=in();m=in();
 53     int u,v;
 54     for(int i=1;i<=n;i++) head[i]=-1;
 55     for(int i=1;i<=m;i++)
 56         u=in(),v=in(),edge[i].u=u,edge[i].v=v,add(u,v); 
 57     int point;
 58     for(int i=1;i<=n;i++){
 59         w[i][i]=1;
 60         point=head[i];
 61         while(point!=-1){
 62             w[i][now]=-(double)1/deg[now];
 63             point=then;
 64         }
 65     }
 66     w[1][n+1]=1;
 67 }
 68 
 69 void Swap(int i,int j,int x){
 70     double t;
 71     for(int k=x+1;k<=n+1;k++)
 72         t=w[i][k],w[i][k]=w[j][k],w[j][k]=t;
 73 }
 74 
 75 void gauss(){
 76     int i,j;
 77     for(i=1,j=1;i<=n && j<=n;i++,j++){
 78         int max_r=i;
 79         for(int k=i+1;k<=n;k++)
 80             if(fabs(w[max_r][j])+eps<fabs(w[k][j]))
 81                 max_r=k;
 82         if(fabs(w[max_r][j])<eps){i--;continue;}
 83         if(max_r!=i) Swap(i,max_r,j);
 84         for(int k=i+1;k<=n;k++){
 85             double rate=w[k][j]/w[i][j];
 86             w[k][j]=0;
 87             for(int l=j+1;l<=n+1;l++)
 88                 w[k][l]-=w[i][l]*rate;
 89         }
 90     }
 91     
 92     for(int i=n;i>=1;i--)
 93         if(fabs(w[i][i])>eps){
 94             double ans_c=w[i][n+1];
 95             for(int k=i+1;k<=n;k++)
 96                 ans_c-=w[i][k]*rec_x[k];
 97             rec_x[i]=ans_c/w[i][i];
 98         }
 99 }
100 
101 void mainwork(){
102     gauss();
103     for(int i=1;i<=m;i++){
104         edge[i].w=rec_x[edge[i].u]/deg[edge[i].u]+rec_x[edge[i].v]/deg[edge[i].v];
105     }    
106     sort(edge+1,edge+m+1,cmp);
107     for(int i=1;i<=m;i++)
108         ans+=edge[i].w*i;
109     printf("%.3lf",ans);
110 }
111 
112 int main(){
113 #ifndef ONLINE_JUDGE
114     freopen("x.in","r",stdin);
115 #endif
116     prework();
117     mainwork();
118     return 0;
119 }
View Code

 

 

[以下是笔者后来发现的问题]

  首先感谢某位不愿意透露姓名的人堆同学复制了我的代码,然后代入了样例,结果:

  

  然后第三行是无解?可是答案却能跑出来...于是我傻了...开始胡乱吹逼[毕竟这么久没打了...]

  

  好吧,然后各种逼都被打败了...(●—●)

  只能认真看看到底出了什么问题,于是发现这个式子有奥妙:

  

  左边的e[i]表示走到i点的期望,右边的e[j]表示走出j点的期望。

  “走到”和“走出”却并不是一样的!

  我们设e[i]表示走到i点的概率,e'[i]表示走出i点的概率。

  如果说i!=n那么走到就能走出,e[i]=e'[i];

  如果i==n那么就有e'[n]=0,e[n]=1他们俩不同...尽管都已知,而我们列式子的时候,将e'[n]作为未知数带进别的点的式子里,但在n自己的式子中却用的是e[n],导致两个变量混淆。

  所以鉴于e'[n]=0,就将建立方程部分修改了一下:

  

  于是现在的式子就发生了变化,最后化出来的矩阵也变成了正常的样子:

  

  这样解出来的就是e[n]是到达n点的期望=1,当然在给边设定权值的时候,我们用的都是e'[i],所以我们手动修改一下e'[n]=0就好了...

  下面是修改过后的代码:

#include <cmath> 
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>using namespace std;#define maxn 520struct Node{int data,next;
}node[maxn*maxn<<1];struct Edge{int u,v;double w;
}edge[maxn*maxn<<1];#define now node[point].data
#define then node[point].nextint n,m,cnt;
int head[maxn],deg[maxn];
const double eps=1e-6;
double w[maxn][maxn],rec_x[maxn],ans;bool cmp(const Edge A,const Edge B){return A.w>B.w;
}inline int in(){int x=0;char ch=getchar();while(ch>'9' || ch<'0') ch=getchar();while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x;
}void add(int u,int v){node[++cnt].data=v;node[cnt].next=head[u];deg[u]++;head[u]=cnt;node[++cnt].data=u;node[cnt].next=head[v];deg[v]++;head[v]=cnt;
}void prework(){n=in();m=in();int u,v;for(int i=1;i<=n;i++) head[i]=-1;for(int i=1;i<=m;i++)u=in(),v=in(),edge[i].u=u,edge[i].v=v,add(u,v); int point;for(int i=1;i<=n;i++){w[i][i]=1;point=head[i];while(point!=-1){if(now!=n) w[i][now]=-(double)1/deg[now];else w[i][now]=0;point=then;}}w[1][n+1]=1;
}void Swap(int i,int j,int x){double t;for(int k=x+1;k<=n+1;k++)t=w[i][k],w[i][k]=w[j][k],w[j][k]=t;
}void gauss(){int i,j;for(i=1,j=1;i<=n && j<=n;i++,j++){int max_r=i;for(int k=i+1;k<=n;k++)if(fabs(w[max_r][j])+eps<fabs(w[k][j]))max_r=k;if(fabs(w[max_r][j])<eps){i--;continue;}if(max_r!=i) Swap(i,max_r,j);for(int k=i+1;k<=n;k++){double rate=w[k][j]/w[i][j];w[k][j]=0;for(int l=j+1;l<=n+1;l++)w[k][l]-=w[i][l]*rate;}}for(int i=n;i>=1;i--)if(fabs(w[i][i])>eps){double ans_c=w[i][n+1];for(int k=i+1;k<=n;k++)ans_c-=w[i][k]*rec_x[k];rec_x[i]=ans_c/w[i][i];}rec_x[n]=0;
}void mainwork(){gauss();for(int i=1;i<=m;i++){edge[i].w=rec_x[edge[i].u]/deg[edge[i].u]+rec_x[edge[i].v]/deg[edge[i].v];}    sort(edge+1,edge+m+1,cmp);for(int i=1;i<=m;i++)ans+=edge[i].w*i;printf("%.3lf",ans);
}int main(){
#ifndef ONLINE_JUDGEfreopen("x.in","r",stdin);
#endifprework();mainwork();return 0;
}
View Code

 

最后再次鸣谢人堆同学提出的问题,有问题才有进步嘛,欢迎大家提问哦...

转载于:https://www.cnblogs.com/Robert-Yuan/p/4636355.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS2019安全函数scanf_s问题

VS2017、VS2019等安全函数scanf_s问题&#xff1a; scanf()、gets()、fgets()、strcpy()、strcat() 等都是C语言自带的函数&#xff0c;它们都是标准函数&#xff0c;但是它们都有一个缺陷&#xff0c;就是不安全&#xff0c;可能会导致数组溢出或者缓冲区溢出&#xff0c;让黑…

eclipse启动tomcat, http://localhost:8080无法访问的解决方案

问题:&#xff1a; tomcat在eclipse里面能正常启动&#xff0c;但在浏览器中访问http://localhost:8080/不能访问tomcat管理页面&#xff0c;且报404错误。同时其他项目页面也不能访问。访问的时候出现下列页面: 现在关闭eclipse里面的tomcat&#xff0c;在tomcat安装目录下双击…

GWT EJB3 Maven JBoss 5.1集成教程

大家好&#xff0c; 在本文中&#xff0c;我们将演示如何正确集成GWT和EJB3 &#xff0c;以实现示例项目&#xff0c;使用maven进行构建并将其部署在JBoss 5.1应用服务器上。 实际上&#xff0c;您可以轻松地更改maven构建文件中的依赖关系&#xff0c;并将项目部署到您喜欢的…

VS2019注释整段代码

VS2019注释整段代码 1.注释 先CTRLK&#xff0c;然后CTRLC 2.取消注释&#xff1a; 先CTRLK&#xff0c;然后CTRLU 顺便写一下&#xff1a; VS code注释整段代码 Alt Shift A 注释 CodeBlocks&#xff1a; CtrlShiftC注释掉当前行或选中部分&#xff0c; CtrlShiftX解除注释…

linux中的开机和关机命令

与关机、重新启动相关的命令 * 将数据同步写入硬盘中的命令 sync * 惯用的关机命令 shutdown * 重新启动、关机 reboot halt poweroff sync 强制将内存中的数据写入到硬盘当中。因为linux系统中&#xff0c;数据会缓存在内存当中&#xff0c;所以为了保证数据完整保存在硬盘…

如何在不到1ms的延迟内完成100K TPS

马丁汤普森&#xff08;Martin Thompson&#xff09;和迈克尔巴克&#xff08;Michael Barker&#xff09;讨论了通过采用一种新的基础架构和软件方法来构建HPC金融系统&#xff0c;以不到1ms的延迟处理超过100K TPS的问题。 一些技巧包括&#xff1a; 了解平台 建模领域 明…

获取时间C语言-按秒数

两部分&#xff1a; 1.获取秒数 2.获取“年-月-日-时-分-秒” 1.获取秒数 #include<time.h>//包含的头文件int GetTime() {time_t t;t time(NULL);//另一种写法是//time(t);//当time&#xff08;&#xff09;内参数为空时结果直接输出&#xff0c;否则就会存储在参数…

Spring的69个知识点

目录 Spring 概述依赖注入Spring beansSpring注解Spring数据访问Spring面向切面编程&#xff08;AOP&#xff09;Spring MVCSpring 概述 1. 什么是spring? Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用&#xff0c;但是有些扩展是针对构建J2EE平台的…

python 编码问题之终极解决

结合之前遇到的坑以及下面贴的这篇文章&#xff0c; 总结几种python乱码解决方案&#xff0c;如果遇到乱码&#xff0c;不妨尝试一下&#xff1f; 1&#xff0c;必备 #encodingutf-8 2, python编程环境编码 import sys reload(sys) sys.setdefaultencoding(utf8) 3,不知道神马…

GWT 2 Spring 3 JPA 2 Hibernate 3.5教程

本分步指南将介绍如何使用开发一个简单的Web应用程序 Google的网络工具包 &#xff08;GWT&#xff09;用于富客户端&#xff0c;而Spring作为后端服务器端框架。 该示例Web应用程序将提供对数据库执行CRUD&#xff08;创建检索更新删除&#xff09;操作的功能。 对于数据访问层…

洛谷P1014 [NOIP1999 普及组] Cantor 表

现代数学的著名证明之一是 Georg Cantor 证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的&#xff1a; 代码 import java.util.*; public class Main{public static void main(String[] args){//int x1 0;int i 0;Scanner sc new Scanner(System.in);int n s…

3522: [Poi2014]Hotel( 树形dp )

枚举中点x( 即选出的三个点 a , b , c 满足 dist( x , a ) dist( x , b ) dist( x , c ) ) , 然后以 x 为 root 做 dfs , 显然两个位于 x 的同一颗子树内的点是不可能被同时选到的 . 我们对 x 的每一颗子树进行 dfs , 记录下当前子树中的点到 x 距离为 d ( 1 < d < n )…

第一冲刺阶段工作总结02

1.昨天&#xff1a; 实验简单的安卓程序&#xff0c;开始具体的设计软件界面。 2.今天&#xff1a; 继续设计软件页面&#xff0c;由于安卓虚拟机过于迟缓&#xff0c;配置真机&#xff0c;学习如何在真机上运行程序。 3.遇到的困难&#xff1a; 真机配置不知道怎样配置&#x…

JBoss 4.2.x Spring 3 JPA Hibernate教程第2部分

我们将继续有关Spring 3 &#xff0c; Hibernate &#xff0c; JPA和JBoss 4.2.x – 4.3集成的教程 。 最后一步是创建一个Spring服务&#xff0c;以向最终用户公开功能。 我们必须创建一个接口类和相关的实现类。 首先是接口类&#xff1a; package com.mycomp.myproject.se…

洛谷P1035 [NOIP2002 普及组] 级数求和

代码 import java.util.Scanner;public class Main {public static void main(String args[]){Scanner sc new Scanner(System.in);int k sc.nextInt();int n 0;double Sn 0;while(Sn<k){n;Sn Sn 1.0/n;}System.out.println(n);} }这样写while循环体这需要每次加上1/…

『Luogu OJ』『C++』Level 1-1

关卡1-1&#xff0c;3道题 洛谷的第一个任务 任务说明&#xff1a;勇敢的迈出第一步&#xff0c;了解下语言和洛谷。跟着书本和老师走&#xff0c;不会难的。 要完成这个任务&#xff0c;请将以下的题目都AC掉&#xff08;即通过这道题目&#xff09;&#xff1a; 1.AB Problem…

Java中的Google ClientLogin实用程序

Google API的身份验证和授权是当今需要与Google服务集成和信息交换的应用程序中的常见功能。 尽管大多数Google身份验证过程是针对Web应用程序量身定制的&#xff0c;但它也可用于桌面和已安装的应用程序。 对于桌面应用程序&#xff0c;Google建议使用称为ClientLogin的身份验…

九度OJ1486 /POJ 1029/2012北京大学研究生复试上机

wa到死&#xff01;wa到死&#xff01;这是一个看着简单&#xff0c;坑及其多的题&#xff01; 坑一&#xff1a;POJ上是单组输入&#xff0c;九度上是多组输入&#xff0c;妈蛋要是研究生复试遇到这种大坑肯定死掉啊&#xff01;而且对于codeforces比较习惯的 同学肯定会觉得巨…

P1046 [NOIP2005 普及组] 陶陶摘苹果

题目描述 陶陶家的院子里有一棵苹果树&#xff0c;每到秋天树上就会结出 1010 个苹果。苹果成熟的时候&#xff0c;陶陶就会跑去摘苹果。陶陶有个 3030 厘米高的板凳&#xff0c;当她不能直接用手摘到苹果的时候&#xff0c;就会踩到板凳上再试试。 现在已知 1010 个苹果到地面…

新手不了解Xcode和mac系统可能犯得错误和我的建议

我是学iOS刚入门的新手&#xff0c;本人装的时黑苹果&#xff0c;我是喜欢完美的人&#xff0c;但黑苹果又是不完美的系统&#xff0c;比如关不了机啊&#xff0c;和显卡驱动不了啊&#xff0c;当自己的电脑出现白屏和卡顿的时候气的没脾气。我是一个新手。开始学的时java但我喜…