题目:有一个小偷要遍历n个城市,每个城市只能走一次,在一个城市他可以选择在这等待5分钟或者选择下一个城市(条件是这下一个城市能把剩下的城市都走完)走,选择某下一个城市与当前停留在原点是等概率的,求遍历完整个图的期望时间。
思路:一共15个城市可以想到状压,dfs一遍把所有的城市的状态都判断下能不能到达vis[u][s],和这种状态下有多少个选择cnt[u][s],然后dp[u][s]表示遍历到u这个点为s状态下,遍历剩下的点还需要用的期望时间。
E[u] = 1 / k * sigma (E[v] + time[u][v]) + 1 / k * (E[u] + 5)
化简得:E[u] = (sigma (E[v] + time[u][v]) + 5) / (k - 1)
#include <bits/stdc++.h>
using namespace std;
struct node{
int v,w;
node(int _v,int _w)
{
v=_v;w=_w;
}
};
vector<node>a[16];
int t,n,m,ma;
int cnt[16][1<<15],vis[16][1<<15];
double dp[16][1<<15];
int dfs1(int u,int s)
{
if(s==ma||vis[u][s]) return vis[u][s]=1;
for(int i=0;i<a[u].size();i++)
{
int v=a[u][i].v;
if((s&(1<<v))||!dfs1(v,s|(1<<v)))
continue;
vis[u][s]=1;
cnt[u][s]++;
}
return vis[u][s];
}
double dfs2(int u,int s)
{
if(s==ma||cnt[u][s]==0) return 0;
if(dp[u][s]>0) return dp[u][s];
double p=1.0/(1+cnt[u][s]);
for(int i=0;i<a[u].size();i++)
{
int v=a[u][i].v;
if((s&(1<<v))==0&&vis[v][s|(1<<v)])
dp[u][s]+=p*(dfs2(v,s|(1<<v))+a[u][i].w);//能够往v走
}
dp[u][s]+=p*5.0;//停留在当前点
dp[u][s]/=(1.0-p);
return dp[u][s];
}
int main()
{
scanf("%d",&t);
int cas=0;
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)
a[i].clear();
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
a[x].push_back(node(y,z));
a[y].push_back(node(x,z));
}
ma=(1<<n)-1;
memset(dp,0,sizeof dp);
memset(vis,0,sizeof vis);
memset(cnt,0,sizeof cnt);
bool flag=dfs1(0,1);
double ans=dfs2(0,1);
printf("Case %d: %.8lf\n",++cas,ans);
}
return 0;
}