[NOI 05]聪聪与可可

聪聪与可可

主文件名:cchkk

时限:1s

【问题描述】

在一个魔法森林里,住着一只聪明的小猫聪聪和一只可爱的小老鼠可可。虽然灰姑娘非常喜欢她们俩,但是,聪聪终究是一只猫,而可可终究是一只老鼠,同样不变的是,聪聪成天想着要吃掉可可。

一天,聪聪意外得到了一台非常有用的机器,据说是叫GPS,对可可能准确的定位。有了这台机器,聪聪要吃可可就易如反掌了。于是,聪聪准备马上出发,去找可可。而可怜的可可还不知道大难即将临头,仍在森林里无忧无虑的玩耍。

小兔子乖乖听到这件事,马上向灰姑娘报告。灰姑娘决定尽快阻止聪聪,拯救可可,可她不知道还有没有足够的时间。

整个森林可以认为是一个无向图,图中有N个美丽的景点,景点从1至N编号。小动物们都只在景点休息、玩耍。在景点之间有一些路连接。

当聪聪得到GPS时,可可正在景点M(M≤N)处。以后的每个时间单位,可可都会选择去相邻的景点(可能有多个)中的一个或停留在原景点不动。而去这些地方所发生的概率是相等的。假设有P个景点与景点M相邻,它们分别是景点R、景点S,……景点Q,在时刻T可可处在景点M,则在(T+1)时刻,可可有1/(P+1)的可能在景点R,有1/(P+1)的可能在景点S,……,有1/(P+1)的可能在景点Q,还有1/(P+1)的可能停在景点M。

我们知道,聪聪是很聪明的,所以,当她在景点C时,她会选一个更靠近可可的景点,如果这样的景点有多个,她会选一个标号最小的景点。由于聪聪太想吃掉可可了,如果走完第一步以后仍然没吃到可可,她还可以在本段时间内再向可可走近一步。

在每个时间单位,假设聪聪先走,可可后走。在某一时刻,若聪聪和可可位于同一个景点,则可怜的可可就被吃掉了。

灰姑娘想知道,平均情况下,聪聪几步就可能吃到可可。而你需要帮助灰姑娘尽快的找到答案。

【输入格式】

从文件cchkk.in中读入数据。

数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数。

第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号。

接下来E行,每行两个整数,第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路。

所有的路都是无向的,即:如果能从A走到B,就可以从B走到A。

输入保证任何两个景点之间不会有多于一条路直接相连,且聪聪和可可之间必有路直接或间接的相连。

【输出格式】

输出到文件cchkk.out中。

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

【输入样例1】

 4 3 1 4 1 2 2 3 3 4

【输出样例1】

1.500

【输入样例2】

 9 9 9 3 1 2 2 3 3 4 4 5 3 6 4 6 4 7 7 8 8 9

【输出样例2】

2.167

【数据范围】

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

对于50%的数据,1≤N≤50。

【题解】

NOI还有这么简单的题么……引用Ivan的话:是人就会做。汗,这话说的我做出来以后一点成就感都没有。

唯一一点要注意的就是别让题目阴了。“灰姑娘想知道,平均情况下,聪聪几步就可能吃到可可。”按着这个做就挂了。一定得看清楚样例分析(我这没贴),否则怎么知道这个“步”是指回合而不是真的指具体的步呢。

要拿50分,floyd预处理+递归下降。要拿满分,bfs预处理+记忆化。我这里用的是spfa,纯是为了复习。好像spfa还快点(bfs我也写了)。

源码:

#include <fstream>
#include <iomanip>
using namespace std;
int V,E,C,K;//节点数、边数、聪聪和可可的初始位置
short neighbor[1001][1001];//[i][0]:节点i连接的边数;[i][j]:节点i的第j个邻居
unsigned short dist[1001][1001];//[i][j]:i、j两点间的最短距离
double dp[1001][1001];
bool walk(short &c,short k){//让聪聪向可可走一步,并返回是否能吃到
    for(short j=1,c0=c,cc;j<=neighbor[c0][0];j++){
        cc=neighbor[c0][j];
        if(dist[c][k]>dist[cc][k]||(dist[c][k]==dist[cc][k]&&c>cc))
            c=cc;
    }
    return c==k;
}
double memo(short c,short k){
    short c0=c;
    if(dp[c][k]>0)    return dp[c][k];
    if(c==k)    return 0;
    if(walk(c,k)||walk(c,k))    return 1;//这句话诡异吧^^
    double ans=memo(c,k);
    for(short j=1;j<=neighbor[k][0];j++)
        ans+=memo(c,neighbor[k][j]);
    ans/=(neighbor[k][0]+1);
    return dp[c0][k]=ans+1;
}
int main(){
    ifstream fin("cchkk.in");
    ofstream fout("cchkk.out");
    fin >> V >> E >> C >> K;
    for(int i,j,k=0;k<E;k++){
        fin >> i >> j;
        neighbor[i][++neighbor[i][0]]=j;
        neighbor[j][++neighbor[j][0]]=i;
    }
    //用SPFA来预处理任意两点间的最短距离
    memset(dist,-1,sizeof(dist));
    for(int s=1;s<=V;s++){
        short queue[1001],head=0,tail=1;
        bool inqueue[1001]={0};
        queue[0]=s,dist[s][s]=0;
        while(head<tail){
            short u = queue[head++];
            inqueue[u]=false;
            if(head>1000)    head=0;
            for(short j=1,v;j<=neighbor[u][0];j++){
                v=neighbor[u][j];
                if(dist[s][v]>dist[s][u]+1){
                    dist[s][v]=dist[s][u]+1;
                    if(!inqueue[v]){
                        queue[tail++]=v,inqueue[v]=true;
                        if(tail>1000)    tail=0;
                    }
                }
            }
        }
    }
    fout << fixed << setprecision(3) << memo(C,K) << endl;
    return 0;
}

可能你对下面的文章也感兴趣:

    分享到:

标签云