感觉这个题的题面描述好坑啊,题目链接:lightoj1287

对于题目的理解是:由于需要时间尽可能长,那么需要尽可能的遍历全图

所以,最终的状态一定是从起点一笔画到了终点,中间无法走重复路径


这样的话,成了一个很经典的问题,n的数值很小,很明显是压缩dp解决这个概率问题

如何求该点的期望:

dp【u】=(5+dp【u】)/(cnt+1)+(mp【u】【i1】+mp【u】【i2】+……mp【u】【icnt】)/(cnt+1),其中,cnt是u合法连接的所有点数,mp【u】【ik】表示边数

如果cnt=0,说明该点是去不了的(看样例3),那么dp【u】=0

化简之后得到公式


设计状态:dp【u】【st】:为当前点在i点,状态为st的期望值(st为二进制压缩的,如st=0110,那么这个状态是去过1,2两个点的)

状态转移:

如果u和i相连那么mp【u】【i】>0

如果st状态中没有i这个点,即st&(1<<i)==0

如果st状态去了i点之后,可以到达终点遍历全图,即dp【i】【st|(1<<i)】>0

那么

dp【u】【st】+=dp【i】【st|(1<<i)】+mp【u】【i】


剩下的细节处理就是记忆化搜索需要做的事情了,代码如下:

int t,n,m;
double mp[maxn][maxn];
double dp[maxn][1<<maxn];
bool vis[maxn][1<<maxn];

int dfs(int st,int u){
	if (st==(1<<n)-1){
		dp[u][st]=0;
		return 1;
	}
	if (vis[u][st]) return dp[u][st]>eps;
	int cnt=0;
	dp[u][st]=5;
	vis[u][st]=true;
	for(int i=0;i<n;i++)
		if (mp[u][i]&&dfs(st|(1<<i),i)&&(!(st&(1<<i)))){
			int st0=st|(1<<i);
			cnt++;
			dp[u][st]+=mp[u][i]+dp[i][st0];
		}
	if (cnt){
		dp[u][st]/=cnt;
		return 1;
	}
	dp[u][st]=0;
	return 0;
}

int main(){
	//input;
	scanf("%d",&t);
	for(int Case=1;Case<=t;Case++){
		memset(dp,0,sizeof(dp));
		memset(mp,0,sizeof(mp));
		memset(vis,false,sizeof(vis));
		scanf("%d%d",&n,&m);
		int u,v,w;
		while(m--){
			scanf("%d%d%d",&u,&v,&w);
			mp[u][v]=mp[v][u]=1.0*w;
		}
		dfs(1,0);
		printf("Case %d: %.10lf\n",Case,dp[0][1]);
	}
	return 0;
}