Where to Run LightOJ - 1287(期望+状压dp+记忆化搜索)

Last night you robbed a bank but couldn't escape and when you just got outside today, the police started chasing you. The city, where you live in, consists of some junctions which are connected by some bidirectional roads.

Since police is behind, you have nothing to do but to run. You don't know whether you would get caught or not, but if it is so, you want to run as long as you can. But the major problem is that if you leave a junction, next time you can't come to this junction, because a group of police wait there for you as soon as you left it, while some other keep chasing you.

That's why you have made a plan to fool the police as longer time as possible. The plan is, from your current junction, you first find the number of junctions which are safe (no police are there) and if you go to one of them; you are still able to visit all the safe junctions (in any order) maintaining the above restrictions. You named them 'Elected Junction' or EJ. If there is no such junction; you stop running, because you lose your mind thinking what to do, and the police catch you immediately.

But if there is at least one EJ, you can either fool around the police by staying in the current junction for 5 minutes (actually you just hide there, so the police lose your track thinking which road you might have taken), or you can choose to go to any EJ. The probability of choosing to stay in the current junction or to go to each of the EJ is equal. For example, from the current junction you can go to three EJs, that means the probability of staying in the current junction is 1/4 or the probability to go to any of the EJ is 1/4 since you have four options (either stay in the current junction or go to any of the three junctions).

You can fool the police (by hiding) multiple times in a city, but of course the above conditions should be satisfied. And you have decided not to stop in the middle of any road, because you have the fear that, if you stop in the middle of any road, then the police would surround you from both ends.

Now, given the map of the city and the required time for you to travel in each road of the map; you have to find the expected time for the police to catch you.

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a blank line. Next line contains two integers n (1 ≤ n ≤ 15) denoting the number of junctions and m, denoting the number of roads in the city. The junctions are numbered from 0 to n - 1.

Each of the next m lines contains three integers u v w (0 ≤ u, v < n, 0 < w ≤ 100, u ≠ v)meaning that there is a road between junction u and v and you need w minutes to travel in the road. Your home is in junction 0 and you are initially in your home. And you may safely assume that there can be at most one road between a pair of junctions.

Output

For each case, print the case number and the expected time in minutes. Errors less than 10-6will be ignored.

Sample Input

3

 

3 2

0 1 3

1 2 3

 

4 6

0 1 75

0 2 86

0 3 4

1 2 1

1 3 53

2 3 10

 

5 5

0 1 10

1 2 20

2 3 30

1 3 20

3 4 10

Sample Output

Case 1: 16

Case 2: 106.8333333333

Case 3: 90

 

题意:从起点0开始,到小偷不能继续走时,所用时间的期望

思路:因为n<15所以考虑用状压来记录走过你城市的状态。

dp[u][sta]表示在u城市,已经访问过城市的状态为sta时,还多少时间期望才能停下来(停下来可能有两种状态,一种是全部城市都访问完,第二种是无法向下一个城市继续走)

先用求期望的思路求出表达式:dp[u][sta]=(5+dp[u][sta])*p+(dp[v][sta2]+dp[u][sta])*p;

p=1/(1+cnt(这个点能走向的城市个数));

化简后dp[u][sta]=(5+dp[v][sta2])/cnt

剩下的就是利用dfs记录cnt的值和完成状态转移了。

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
#include <stack>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
#define inf 0x3f3f3f3f
int head[maxn];
int num;
int n,m;
double dp[16][1<<16];
bool vis[16][1<<16];
struct Edge
{
    int u,v,w,next;
}edge[maxn];

void addEdge(int u,int v,int w)
{
    edge[num].u=u;
    edge[num].v=v;
    edge[num].w=w;
    edge[num].next=head[u];
    head[u]=num++;
}

void init()
{
    memset(head,-1,sizeof(head));
    memset(dp,0,sizeof(dp));
    memset(vis,0,sizeof(vis));
    num=0;
}
bool dfs(int u,int sta)
{
    if(sta==(1<<n)-1)//所有的城市都被访问过,代表当前已经是结束点
    {
        dp[u][sta]=0;
        return 1;
    }
    if(vis[u][sta])//如果这个点已经被访问,那只需要看它能不能继续转移
    {
        if(dp[u][sta]>0)
        {
            return true;
        }
        return false;
    }
    vis[u][sta]=1;
    dp[u][sta]=5.0;//即使不走向下一个点,也可以呆5分钟
    int cnt=0;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v,w=edge[i].w;
        if((sta&(1<<v))==0&&dfs(v,sta|(1<<v)))
        {
            cnt++;
            dp[u][sta]+=dp[v][sta|(1<<v)]+w;
        }
    }
    if(cnt==0)
    {
        dp[u][sta]=0;//没有点可以继续转移
        return 0;
    }
    dp[u][sta]=dp[u][sta]/(cnt);
    return 1;
}
int main(int argc, char const *argv[])
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int T;
    int Case=0;
    cin>>T;
    while(T--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            addEdge(x,y,w);
            addEdge(y,x,w);
        }
        dfs(0,1);
        printf("Case %d: %.6lf\n",++Case,dp[0][1]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40774175/article/details/81564934