BZOJ 1415 NOI2005 聪聪和可可 期望DP+记忆化搜索 BZOJ200题达成&&NOI2005全AC达成

题目大意:给定一个无向图,聪聪在起点,可可在终点,每个时刻聪聪会沿最短路走向可可两步(如果有多条最短路走编号最小的点),然后可可会等概率向周围走或不动,求平均多少个时刻后聪聪和可可相遇

今天早上起床发现194了然后就各种刷……当我发现199的时候我决定把第200题交给05年NOI仅剩的一道题……结果尼玛调了能有一个小时……我居然没看到编号最小这个限制0.0

首先我们知道,由于聪聪走两步而可可走一步,所以聪聪一定能在有限的时刻追上可可,而且两人的距离随着时间进行单调递减

于是我们记忆化搜索

首先用预处理出一个数组p[i][j],表示当聪聪在点i,可可在点j时聪聪下一步走哪个点 这个从每个点出发跑一遍SPFA就可以处理出来

然后就可以记忆化搜索了 令f[i][j]为当聪聪在点i,可可在点j时的期望相遇时

若i==j 则f[i][j]=0

若p[i][j]==j||p[p[i][j]][j]==j则f[i][j]=1

否则令temp=p[p[i][j]][j],则有

其中degree[j]表示j的连边数量

然后就水过了~ 注意多条最短路的时候走编号最小的点

#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<algorithm>
#define M 1010
using namespace std;
struct abcd{
	int to,f,next;
}table[M<<1];
int head[M],tot;
int n,m,s,t;
int degree[M],p[M][M];
double f[M][M];
void Add(int x,int y)
{
	degree[x]++;
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}
void SPFA(int st)
{
	static int f[M],q[65540],v[M],from[M];
	static unsigned short r,h;
	int i;
	memset(f,0x3f,sizeof f);
	f[st]=0;q[++r]=st;
	while(r!=h)
	{
		int x=q[++h];
		v[x]=0;
		for(i=head[x];i;i=table[i].next)
			if(f[table[i].to]>f[x]+1||f[table[i].to]==f[x]+1&&x<from[table[i].to])
			{
				f[table[i].to]=f[x]+1;
				from[table[i].to]=x;
				if(!v[table[i].to])
					v[table[i].to]=1,q[++r]=table[i].to;
			}
	}
	for(i=1;i<=n;i++)
		if(i!=st)
			p[i][st]=from[i];
}
double Memorial_Search(int x,int y)
{
	int i;
	if(x==y) return f[x][y]=0;
	if(p[x][y]==y) return f[x][y]=1;
	if(p[p[x][y]][y]==y) return f[x][y]=1;
	if(f[x][y]>=-1e-7) return f[x][y];
	int temp=p[p[x][y]][y];
	double re=1;
	for(i=head[y];i;i=table[i].next)
		re+=Memorial_Search(temp,table[i].to)/(degree[y]+1);
	re+=Memorial_Search(temp,y)/(degree[y]+1);
	return f[x][y]=re;
}
int main()
{
	int i,x,y;
	cin>>n>>m>>s>>t;
	for(i=1;i<=m;i++)
		scanf("%d%d",&x,&y),Add(x,y),Add(y,x);
	for(i=1;i<=n;i++)
		SPFA(i);
	memset(f,0xc2,sizeof f);
	cout<<fixed<<setprecision(3)<<Memorial_Search(s,t)<<endl;
}
时间: 2024-10-24 06:56:02

BZOJ 1415 NOI2005 聪聪和可可 期望DP+记忆化搜索 BZOJ200题达成&&NOI2005全AC达成的相关文章

【BZOJ1415】【Noi2005】聪聪和可可 概率DP 记忆化搜索

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46457811"); } 题解: 记忆化搜索. f(i,j) 表示猫在 i .鼠在 j 时的期望. 然后显然它是拓扑的,然后先枚举起点n遍bfs算出 f(i,j) 时猫只走一步应该到哪个节点,然后对于 f(i,j) 枚

[期望dp+记忆化搜索] light oj 1038 Race to 1 Again

题意: 给一个数n,每次随机选它的一个约数去除n,直到除到1为止,问除的次数的期望. 思路: E[n]= E[n/a[1]]/cnt+E[n/a[2]]/cnt+...+E[n/a[n]]/cnt+1 a[i]为n的约数,cnt为约数的个数. 显然a[i]=1  则(1-1/cnt)E[n]=E[n/a[2]]/cnt+...+E[n/a[n]]/cnt+1 记忆化搜索就ok了~ 代码: #include"cstdlib" #include"cstdio" #inc

TSP+期望——lightoj1287记忆化搜索,好题!

感觉是很经典的题 记忆化时因为不好直接通过E判断某个状态是否已经求过,所以再加一个vis打标记即可 /*E[S][u]表示从u出发当前状态是S的期望*/ #include<bits/stdc++.h> using namespace std; #define N 16 #define INF 0x3f3f3f3f int mp[N][N],n,m; double E[N][1<<N]; bool vis[N][1<<N]; bool dfs(int S,int root

【BZOJ 1415】 1415: [Noi2005]聪聪和可可 (bfs+记忆化搜索+期望)

1415: [Noi2005]聪聪和可可 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1640  Solved: 962 Description Input 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数. 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号. 接下来E行,每行两个整数,第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路. 所有的路都是无向的,即

BZOJ.2246.[SDOI2011]迷宫探险(DP 记忆化搜索 概率)

题目链接 求最大的存活概率,DP+记忆化. 用f[s][x][y][hp]表示在s状态,(x,y)点,血量为hp时的存活概率. s是个三进制数,记录每个陷阱无害/有害/未知. 转移时比较容易,主要是在陷阱未知时需要知道当前状态这个陷阱为有害/无害的概率,并用这两个概率相加. 如何求某个状态下未知陷阱是否有害的概率呢(以下求有害概率,即 有害/(有害+无害)) DFS枚举每个陷阱已知有害/无害/未知的状态,我们需要处理未知陷阱在该状态下的概率. 枚举每个未知的陷阱,再枚举2^K的概率数组,只有当满

bzoj 1638: [Usaco2007 Mar]Cow Traffic 奶牛交通【记忆化搜索】

震惊!记忆化搜索忘记返回map值调了半小时! 边(u,v)的经过次数是:能到u的牛数*v到n的方案数.正反两次连边,dfs两次即可 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=5005,M=50005; int n,m,x[M],y[M],h[N],cnt,ans,f[N],g[N]; struct qwe { int ne,to; }e[M

【bzoj1415】[Noi2005]聪聪和可可 期望记忆化搜索

题目描述 输入 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数. 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号. 接下来E行,每行两个整数,第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路. 所有的路都是无向的,即:如果能从A走到B,就可以从B走到A. 输入保证任何两个景点之间不会有多于一条路直接相连,且聪聪和可可之间必有路直接或间接的相连. 输出 输出1个实数,四舍五入保留三位小数,表示平均多少个时间单

poj 3156 hash+记忆化搜索 期望dp

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int n,m; #define N 32 #define mod 10007LL #define mod2 10000007 #define inf 0x3fffffff typedef long long ll; typedef double dd; int f[N]

[BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】

题目链接:BZOJ - 1055 题目分析 这种类似区间 DP 的记忆化搜索都是很相近的,比如字符串压缩和字符串扩展都差不多. 都是将现在 Solve 的区间分成子区间,再求解子区间. 这道题 Solve(l, r, x) 求能否将 [l, r] 的区间还原成 x ,那么就将它分成两段,看是否能左段变成 p , 右段变成 q. (x 能变成 pq) 代码 #include <iostream> #include <cstdio> #include <cstdlib> #