zoukankan      html  css  js  c++  java
  • [NOI2005]聪聪与可可

    XII.[NOI2005]聪聪与可可

    这题一个naive的思路是设\(p_{i,j}\)表示\(i\)时刻老鼠在位置\(j\)的概率,然后求出\(f_i\)表示猫\(i\)时刻前抓到老鼠的概率(因为如果\(i\)时刻猫可以抓到老鼠,则\(i+1\)时刻猫一定仍可以抓到老鼠;而\(i\)时刻猫能抓到老鼠的位置只有可能距猫的起点\(\leq 2i\)),最后差个分就能得出答案。

    但是我们发现猫并不能保证所有\(\leq 2i\)的位置都能抓到——举例子来说,我们有这样一个样例:

    猫从\(1\)出发,第一时刻到达\(3\);但是,如果老鼠此时走到了\(5\),虽然\(1\)\(5\)的距离\(\leq 2i=2\),但是猫仍不能一次抓到老鼠。

    所以我们不得不考虑一种新的想法,即记录下猫和鼠的位置,求出此时它期望多少轮能够捉到鼠。

    我们设\(f_{i,j}\)表示猫在\(i\)时,鼠在\(j\)时的期望次数;我们再设\(nex2_{i,j}\)表示此时猫下一步会走到哪里。\(nex2\)可以通过\(O(nm)\)地预处理出来距离数组,再\(O(nm)\)地预处理出来\(nex1\)数组表示猫走一步的目标,然后通过\(nex1\)预处理出来\(nex2\)得出。

    则有:

    \(f_{i,j}=0\),如果\(i=j\)

    \(f_{i,j}=1\),如果猫能直接从\(i\)走到\(j\)

    否则,设这里有一条边\((j,k)\),则有

    \[f_{i,j}=\dfrac{f_{nex2_{i,j},j}\sum f_{nex2_{i,j},k}}{deg_k+1} \]

    凭直觉发现这不可能有环;故直接记忆化搞掉即可。

    时间复杂度\(O(nm)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,dis[1010][1010],nex1[1010][1010],nex2[1010][1010],cat,mouse;
    double f[1010][1010];
    bool vis[1010][1010];
    vector<int>v[1010];
    void bfs(int S){
    	queue<int>q;
    	memset(dis[S],0x3f,sizeof(dis[S])),dis[S][S]=0;
    	q.push(S);
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for(auto y:v[x])if(dis[S][y]==0x3f3f3f3f)dis[S][y]=dis[S][x]+1,q.push(y);
    	}
    }
    double dfs(int x,int y){
    	if(vis[x][y])return f[x][y];
    	vis[x][y]=true;
    	double &now=f[x][y];
    	if(x==y)return now=0;
    	if(nex2[x][y]==-1)return now=1;
    	x=nex2[x][y];
    	for(auto z:v[y])now+=dfs(x,z)+1;
    	now+=dfs(x,y)+1;
    	now/=int(v[y].size()+1);
    	return now;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	scanf("%d%d",&cat,&mouse);
    	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
    	for(int i=1;i<=n;i++)bfs(i);
    //	for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",dis[i][j]);puts("");}
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
    		if(dis[i][j]==0x3f3f3f3f)continue;
    		if(dis[i][j]<=1){nex1[i][j]=-1;continue;}
    		int mp=-1;
    		for(auto k:v[i])if(mp==-1||dis[mp][j]>dis[k][j]||dis[mp][j]==dis[k][j]&&mp>k)mp=k;
    		nex1[i][j]=mp;
    	}
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
    		if(dis[i][j]==0x3f3f3f3f)continue;
    		if(nex1[i][j]==-1||nex1[nex1[i][j]][j]==-1){nex2[i][j]=-1;continue;}
    		nex2[i][j]=nex1[nex1[i][j]][j]; 
    	}
    //	for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)printf("%d ",nex2[i][j]);puts("");}
    //	for(int i=1;i<=n;i++)printf("%d ",dis[i]);puts("");
    	printf("%.3lf\n",dfs(cat,mouse));
    	return 0;
    } 
    

  • 相关阅读:
    贪心例题
    第十六周总结
    软件工程个人课程总结
    冲刺二十一天
    浅谈async/await
    浅谈设计模式的六大原则
    dotnetcore配置框架简介
    这一次,终于弄懂了协变和逆变
    科个普:进程、线程、并发、并行
    五分钟了解Semaphore
  • 原文地址:https://www.cnblogs.com/Troverld/p/14610986.html
Copyright © 2011-2022 走看看