LightOJ 1287 Where to Run 期望DP+状压+记忆化搜索

Where to Run LightOJ - 1287

给一个有 nn 个结点,mm 条边的无向图,从 00 出发,定义 EJEJ 为未访问过的结点,并且通过该结点仍然能够遍历全图,假设当前结点的 EJEJ 结点有 cntcnt 个,在当前结点时可以进行如下选择:

(1)在当前结点待 55 分钟
(2)以相同概率在 EJEJ 中选一个结点走下去

当走到图中最后一个结点时被警察抓住,求被警察抓住的期望时间是多少?

因为 n15n\le 15 ,因此可以考虑状态压缩,用 dp[i][s]dp[i][s] 表示当前结点是 ii ,当前状态是 ss 时遍历完全图的期望时间,其中 ss 的二进制表示当前已经访问的结点。

Ei\mathcal{E}_i 为结点 iiEJEJ 集合,Ei|\mathcal{E}_i| 为集合大小,则

dp[i][s]=1Ei+1(dp[i][s]+5)+1Ei+1jEi(dp[j][s(1<<j)]+w[i][j])dp[i][s]=5Ei+1EijEi(dp[j][s(1<<j)]+w[i][j]) \begin{aligned} dp[i][s]&=\frac{1}{|\mathcal{E}_i|+1}(dp[i][s]+5)+\frac{1}{|\mathcal{E}_i|+1}\sum_{j\in\mathcal{E}_i}(dp[j][s|(1<<j)]+w[i][j])\\ dp[i][s]&=\frac{5}{|\mathcal{E}_i|}+\frac{1}{|\mathcal{E}_i|}\sum_{j\in\mathcal{E}_i}(dp[j][s|(1<<j)]+w[i][j])\\ \end{aligned}

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
//#define WINE
#define MAXN 20
#define MAXM 300
using namespace std;
int T,iCase,n,m,cnt,u,v,w,head[MAXN];
double dp[MAXN][1<<15];
bool vis[MAXN],mem[MAXN][1<<15];
struct Edge{
    int to,w,nxt;
}edge[MAXM];
void addedge(int u,int v,int w){
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt++;
}
void dfs(int u,int s){
    if(mem[u][s])return ;
    int k=0;double sum=0;
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to,w=edge[i].w;
        if(vis[v])continue;
        int ns=s|(1<<v);
        vis[v]=true;dfs(v,ns);vis[v]=false;
        if(mem[v][ns]){
            mem[u][s]=true;
            k++;sum+=dp[v][ns]+w;
        }
    }
    if(s==((1<<n)-1))mem[u][s]=true;
    if(k!=0)dp[u][s]=(5.0+sum)/k;
}
int main(){
#ifdef WINE
    freopen("data.in","r",stdin);
#endif
    scanf("%d",&T);
    while(T--){
        memset(vis,false,sizeof(vis));
        memset(mem,false,sizeof(mem));
        memset(head,-1,sizeof(head));
        memset(dp,0,sizeof(dp));
        cnt=0;
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);addedge(v,u,w);
        }
        vis[0]=true;
        dfs(0,1);
        printf("Case %d: %.8lf\n",++iCase,dp[0][1]);
    }
    return 0;
}

在这里插入图片描述

posted @ 2020-03-26 10:56  winechord  阅读(92)  评论(0编辑  收藏  举报