您的位置:首页 > 其它

NOI2005 BZOJ 1415聪聪和可可(期望+Floyd)

2017-03-17 11:42 274 查看


一道和换教室思想差不多的题(怀疑换教室就是这个改的),老样子用Floyd算出每2个点直接的距离,然后进行期望的计算(我这里用的记忆化搜索,个人爱好,比较这样代码短)。

我们设f(i,j)为猫在i位置,老鼠在j位置的期望值(名字不想打了),如果他们在同一位置显然直接吃就好,期望为0.

同样的如果距离小于等于2,猫可以直接跑过去,期望为1.

接下来就是大于2的情况了,我们先让猫按题目描述走2步,老鼠走一步,得到位置x和y,然后我们直接询问f(x,y)就可以了。

所以方程如下:

f(i,j)=sum{f(x,y)}/t+1;

其中t为老鼠走的方案数。

详细代码如下:

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1005;
const int inf=20000005;

struct edge
{
int u,v,next;
}e[maxn*2];
int fist[maxn]={0},cnt=0;
int d[maxn][maxn];
double f[maxn][maxn]={0};
int n,m;

void add(int x,int y)
{
e[++cnt]=(edge){x,y,fist[x]};fist[x]=cnt;
e[++cnt]=(edge){y,x,fist[y]};fist[y]=cnt;
}
int work(int x,int y)
{
int z=inf,j;
for(int k=fist[x];k;k=e[k].next)
{
j=e[k].v;
if(d[j][y]>=d[x][y]) continue;
if(j<z) z=j;
}
x=z;
z=inf;
for(int k=fist[x];k;k=e[k].next)
{
j=e[k].v;
if(d[j][y]>=d[x][y]) continue;
if(j<z) z=j;
}
x=z;
return x;
}
double run(int x,int y)
{
if(f[x][y]) return f[x][y];
if(d[x][y]==0) return f[x][y]=0;
if(d[x][y]<=2) return f[x][y]=1;
int xx=work(x,y);
int t=0,j;
for(int k=fist[y];k;k=e[k].next)
{
j=e[k].v;
t++;
f[x][y]+=run(xx,j)+1;
}
f[x][y]+=run(xx,y)+1;
t++;
return f[x][y]/=t;
}
void init()
{
int x,y,a,b;
scanf("%d%d",&n,&m);
scanf("%d%d",&a,&b);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) if(j!=i)
d[i][j]=inf;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
d[x][y]=d[y][x]=1;
add(x,y);
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)if(i!=k&&d[i][k]!=inf)
for(int j=1;j<=n;j++)if(j!=k&&i!=j&&d[k][j]!=inf)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
printf("%.3lf",run(a,b));
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
init();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: