BZOJ 1415聪聪和可可 期望dp

来源:互联网 发布:在线财神网淘宝店 编辑:程序博客网 时间:2024/05/17 01:54

1415: [Noi2005]聪聪和可可

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 1750 Solved: 1026
[Submit][Status][Discuss]
Description

Input

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

输出1个实数,四舍五入保留三位小数,表示平均多少个时间单位后聪聪会把可可吃掉。
Sample Input

【输入样例1】

4 3

1 4

1 2

2 3

3 4

【输入样例2】

9 9

9 3

1 2

2 3

3 4

4 5

3 6

4 6

4 7

7 8

8 9

Sample Output

【输出样例1】

1.500

【输出样例2】

2.167

HINT

对于所有的数据,1≤N,E≤1000。
对于50%的数据,1≤N≤50。

首先对于聪聪,他在s点时,可可在t点时,他下一步走的位置road[s][t]是确定的,所以我们可以利用广搜(SPFA)预处理出聪聪在点i,可可在点j时聪聪的下一步road[i][j]。//其实这一步的处理还是需要一点技巧
接下来就是转移的部分了。
设f[i][j]表示聪聪在i点,可可在j点时还期望多少步聪聪可以吃掉可可,不难得出f[i][j]可以从f[road[road[s][t]][t]][v]转移而来,v表示可可下一步所有可能的位置,包括当前的t,而每一个的概率为1/(q[t]+1)//q[t]表示t点的出度数
不要忘了每次f[i][j]+=1 毕竟又要走一步了。

一定要读题啊!读题啊!
1 聪聪先走可可后走
2.聪聪要是没吃到可可一次可以走两步 这就直接决定了附初始值:
road[road[s][t]][t]==t 或road[s][t]==t 时
f[s][t]=1.0.
当s==t 时,f[s][t]=0 //显然

代码:

#include<cstdio>#include<cstring>using namespace std;const int N = 1000 + 10;const int M = 2000 + 10;const int INF = 0x73f3f3f;int n,m;int s,t;struct node{    int pre,v;}edge[M];int num=0;int head[M];void addedge(int from,int to){    num++;    edge[num].pre=head[from];    edge[num].v=to;    head[from]=num;}int road[N][N];//road[i][j]表示聪聪在i时,可可在j时下一步应该移动到的点  int dis[N];int state[N*10];bool vis[N];#define ms(x,y) memset(x,y,sizeof(x))void SPFA(int s){//之前谁写的广搜求最短路啊     int h=0,tail=1;    ms(dis,INF);ms(state,0);ms(vis,0);    state[1]=s,dis[s]=0,vis[s]=true;    do{        h++;        int u=state[h];vis[s]=false;        for(int i=head[u];i;i=edge[i].pre){            int v=edge[i].v;            if(dis[v]>dis[u]+1){                dis[v]=dis[u]+1;                if(!vis[v]){                    vis[v]=true;                    tail++;                    state[tail]=v;                }            }        }    }    while(h<tail);}double f[N][N];int q[N];double dfs(int s,int t){    if(f[s][t]) return f[s][t];    if(s==t) return 0;//在同一个地方     if(road[road[s][t]][t]==t||road[s][t]==t) return f[s][t]=1.0;    double ans=dfs(road[road[s][t]][t],t);    for(int i=head[t];i;i=edge[i].pre){        int v=edge[i].v;        ans+=dfs(road[road[s][t]][t],v);    }    return f[s][t]=ans/(q[t]+1)+1;}int main(){    ms(q,0);    scanf("%d%d",&n,&m);    scanf("%d%d",&s,&t);    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            f[i][j]=0.0;    for(int i=1;i<=m;i++){        int u,v;        scanf("%d%d",&u,&v);        q[u]++,q[v]++;        addedge(u,v);        addedge(v,u);    }    for(int i=1;i<=n;i++){        SPFA(i);        for(int j=1;j<=n;j++){            int mmax=INF;            for(int k=head[j];k;k=edge[k].pre){                int v=edge[k].v;                if(dis[v]<mmax||dis[v]==mmax&&v<road[j][i]){                    mmax=dis[v];                    road[j][i]=v;                }            }        }    }//终于找出聪聪怎么走了    //for(int i=1;i<=n;i++)      //  printf("%d ",road[4][i]);//连边完美     printf("%0.3lf",dfs(s,t));    return 0;}
原创粉丝点击