LightOJ 1287 Where to Run 期望DP+状压+记忆化搜索
给一个有 个结点, 条边的无向图,从 出发,定义 为未访问过的结点,并且通过该结点仍然能够遍历全图,假设当前结点的 结点有 个,在当前结点时可以进行如下选择:
(1)在当前结点待 分钟
(2)以相同概率在 中选一个结点走下去
当走到图中最后一个结点时被警察抓住,求被警察抓住的期望时间是多少?
因为 ,因此可以考虑状态压缩,用 表示当前结点是 ,当前状态是 时遍历完全图的期望时间,其中 的二进制表示当前已经访问的结点。
设 为结点 的 集合, 为集合大小,则
代码如下:
#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;
}