zoukankan      html  css  js  c++  java
  • 【CF679D】Bear and Chase 最短路+乱搞

    【CF679D】Bear and Chase

    题意:近日,鼠国的头号通缉犯,神出鬼没的怪盗——Joker正于摩登市出没!对于名侦探Jack来说,这正是将其捉拿归案的大号时机。形式化地,摩登市可以看成一张 $n$ 个点,$m$ 条边的简单无向连通图。Jack有一个神奇的探测器:MC(Mouse Chaser)。当Jack在某个城市使用MC时,MC会显示Joker所在城市与Jack所在城市之间的距离(即最短路所经过的边数)。Jack只有两天的时间捉拿Joker,具体过程如下:

    1.第一天,Joker随机潜伏在某个城市,即Joker位于每个城市的概率都是 $1over n$ 。Jack将挑选一个城市 $a$ ,在 $a$ 处使用MC,得知Joker所在城市与 $a$ 的距离。然后Jack可以选择立刻调查某个城市:如果Joker正好位于被调查的城市,则Jack成功地将Joker捉拿归案(如果Joker刚好位于城市 $a$ ,那么MC会显示 $0$ ,显然Jack直接调查城市 $a$ 就能直接将Joker捉拿归案);否则,Joker会意识到自己正被追查,从而立刻逃离摩登市,导致Jack的任务直接失败!

    2.如果第一天没有立刻调查。那么在夜里,Joker会随机选择一个与Joker所在城市相邻的城市,并前往该城市。即如果有 $d$ 个城市与Joker所在城市相连,则Joker有 $1over d$ 的概率前往其中的每个城市。

    3.第二天,Jack将挑选一个城市 $b$ ,在 $b$ 处使用MC(忽略Jack从 $a$ 前往 $b$ 的时间),得知Joker所在城市与 $b$ 的距离。然后Jack必须选择一个城市进行调查。如果Joker刚好位于被调查的城市,则Jack成功的将Joker捉拿归案;否则,Jack的任务失败。

    现在,请你帮助Jack,制定合适的追捕计划,选择前往调查的城市,使得Jack将Joker捉拿归案的概率最大。输出这个最大的概率。

    $2le nle 400,n-1le mle {n(n-1)over 2},1le x,yle n$

    题解:先考虑暴力的解法。我们枚举两次使用MC的城市a和b,然后用f[i][j]表示第一天显示i,第二天显示j的概率。我们得到f[i][j]后,用f数组求出g[i]表示第一天在a使用MC显示i的最大概率,进而得到在a使用MC的最大总概率。这样做的复杂度显然是$O(n^4)$的。

    但是我们发现,如果我们枚举了第一天可能的位置x,则i=dis[a][x],j只能等于dis[b][x]-1,dis[b][x],dis[b][x]+1。我们可以进行一些预处理,然后复杂度就降到$O(n^3)$了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
    typedef double db;
    int n,m,now;
    int f[410][410],pa[100000],pb[100000],d0[410][410],d1[410][410],d2[410][410],d[410],vis[410][410],cnt[410];
    db s0[410][410],s1[410][410],s2[410][410],p[410][410],s[410];
    vector<int> v[410];
    vector<int>::iterator it;
    db tmp,ans;
    inline void upd(db &x,db y) {if(x<y)	x=y;}
    inline void upd(int a,int b,db x)
    {
    	if(a<0)	return ;
    	if(vis[a][b]!=now)	vis[a][b]=now,p[a][b]=0,v[a].push_back(b);
    	upd(p[a][b],x);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	memset(f,0x3f,sizeof(f));
    	int i,j,k,a,b;
    	for(i=1;i<=n;i++)	f[i][i]=0;
    	for(i=1;i<=m;i++)	scanf("%d%d",&a,&b),pa[i]=a,pb[i]=b,d[a]++,d[b]++,f[a][b]=f[b][a]=1;
    	for(k=1;k<=n;k++)
    	{
    		for(i=1;i<=n;i++)	for(j=1;j<=n;j++)	f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
    	}
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=m;j++)
    		{
    			if(f[i][pb[j]]==f[i][pa[j]]+1)	s1[i][pa[j]]+=1.0/n/d[pb[j]],s2[i][pb[j]]+=1.0/n/d[pa[j]];
    			if(f[i][pa[j]]==f[i][pb[j]]+1)	s1[i][pb[j]]+=1.0/n/d[pa[j]],s2[i][pa[j]]+=1.0/n/d[pb[j]];
    			if(f[i][pa[j]]==f[i][pb[j]])	s0[i][pa[j]]+=1.0/n/d[pb[j]],s0[i][pb[j]]+=1.0/n/d[pa[j]];
    		}
    	}
    	for(i=1;i<=n;i++)
    	{
    		memset(cnt,0,sizeof(cnt)),memset(s,0,sizeof(s));
    		for(j=1;j<=n;j++)	cnt[f[i][j]]++;
    		for(j=0;j<=n;j++)	if(cnt[j])	s[j]=1.0/n;
    		for(j=1;j<=n;j++)
    		{
    			now++;
    			for(k=1;k<=n;k++)
    			{
    				upd(f[i][k],f[j][k],s0[i][k]);
    				upd(f[i][k]+1,f[j][k],s1[i][k]);
    				upd(f[i][k]-1,f[j][k],s2[i][k]);
    			}
    			for(k=0;k<=n;k++)
    			{
    				tmp=0;
    				for(it=v[k].begin();it!=v[k].end();it++)	tmp+=p[k][*it];
    				v[k].clear();
    				upd(s[k],tmp);
    			}
    		}
    		tmp=0;
    		for(j=0;j<=n;j++)	tmp+=s[j];
    		ans=max(ans,tmp);
    	}
    	printf("%.12lf",ans);
    	return 0;
    }//6 14 1 6 2 6 3 6 4 6 5 6 1 5 2 5 3 5 4 5  2 4 3 4 1 3 2 3 1 2
  • 相关阅读:
    交换相邻字符(CharBuffer)
    ANSI和UNICODE
    关键路径
    拓扑排序 java
    MySql 中group by使用
    面试题2
    面试题
    K8S如何限制资源使用
    Kubernetes中配置Pod的liveness和readiness探针
    sed入门详解教程
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8598952.html
Copyright © 2011-2022 走看看