首页 > ACM题库 > HDU-杭电 > HDU 3409-Chase-动态规划-[解题报告]HOJ
2014
03-23

HDU 3409-Chase-动态规划-[解题报告]HOJ

Chase

问题描述 :

Jack the Robber appears again! He just robbed a bank in town and is running away with a huge amount of dollar cash. Senior FBI agent Don Epps is taking responsibility to catch him. He must deploy his men immediately to hold up and capture Jack on some spot in town. Because this task is extremely urgent and crucial, Don asks his brother Charlie Epps, the mathematics professor in the University of CalSci, to help him find the theoretically best deployment.

Let us assume that the town can be described as N spots (numbered from 0 to N-1) and M bidirectional roads between those N spots. Jack the Robber starts running from Spot 0. After several rounds of chasing and fleeing in the past, Don summarized Jack’s rules of escape:

1.He will never visit a spot more than once.

2.He is an expert about the geography of this town, so no matter which spot he reaches, the route he has traveled is always the shortest path from Spot 0 to that spot. To simplify the situation, we assume that there is only one shortest path from Spot 0 to any other spot.

3.He has no certain destination spot to go. He just runs AS FAR AS HE CAN, following the two rules above. As you may see, if he never gets caught, he will definitely come to a spot where he has to stop because if he keeps running, he will violate the two rules above. When he reaches a spot where he has to stop and is not arrested by FBI at that spot, he hides and FBI will never find him.

4.When he comes to a spot and is NOT captured by FBI at that spot, he will randomly choose a road to continue running. Of course, his choice can’t conflict with the above mentioned rules. The term “randomly” means that he chooses each valid road on the same probability.

Even if Jack gets to a spot where agents are already deployed, he may still get a chance to run away. For example, if the spot is very crowded, even all agents are deployed there, Jack may still run away easily. So Charlie finds out an N×(P+1) probability matrix PT. PT(i, j) represents the probability of j FBI agents deployed at spot i arresting Jack when Jack comes to Spot i. For example, PT(0, 1) can be only 5%, which means sending only 1 agent to the initial spot may miss the target in large probability, because the agent may be killed by Jack. In another case, if Spot 5 is suitable for capturing and 10 agents are deployed there, PT(5, 10) may be over 80%. Of cause, PT(i, 0) is always 0.

According to the given matrix PT, you need to help Charlie to figure out the best way to deploy agents in which the probability of catching the robber reaches the maximum.

输入:

Input contains several test cases. In the first line of each case, there are two integers N (N<=100) and M (M<=10000), representing the number of spots and the number of roads between them.

Next M lines describe all roads. In each line, there are three integers a, b and c (0<=a, b<N, 0<c<=10000), representing a road of length c between Spot a and Spot b. Pay attention that there may be more than one roads between two spots, as well as some roads may come into a self-loop (a=b).

The following line contains an integer P (0<P<=50), representing the total number of agents. Following N lines describe the probability matrix PT. PT(i,j) (0<= PT(i,j)<=1) represents the probability that robber can be captured by j FBI agents in Spot i when he comes to Spot i . We don’t give the leftmost column of the matrix for they are all zero, so the matrix only has P columns. In other words, the first number you read from the matrix is PT(0,1) .

The input file ends with a line that contains “0 0”.

输出:

Input contains several test cases. In the first line of each case, there are two integers N (N<=100) and M (M<=10000), representing the number of spots and the number of roads between them.

Next M lines describe all roads. In each line, there are three integers a, b and c (0<=a, b<N, 0<c<=10000), representing a road of length c between Spot a and Spot b. Pay attention that there may be more than one roads between two spots, as well as some roads may come into a self-loop (a=b).

The following line contains an integer P (0<P<=50), representing the total number of agents. Following N lines describe the probability matrix PT. PT(i,j) (0<= PT(i,j)<=1) represents the probability that robber can be captured by j FBI agents in Spot i when he comes to Spot i . We don’t give the leftmost column of the matrix for they are all zero, so the matrix only has P columns. In other words, the first number you read from the matrix is PT(0,1) .

The input file ends with a line that contains “0 0”.

样例输入:

4 4
0 1 1
0 2 2
1 3 3
2 3 1
2
0.01 0.1
0.5 0.8
0.5 0.8
0.7 0.9
0 0

样例输出:

60.00

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3409

参考博客:http://www.cnblogs.com/woaishizhan/p/3189813.html

Chase

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 205;
const int maxe = 20500;
const int INF = 0x3f3f3f;

struct Edge{
    int u,v,w;
    int next;
    void assign(int u_,int v_,int w_,int next_){
        u = u_;  v = v_;   w = w_;  next = next_;
    }
    bool operator < (const Edge& e) const {
        return w > e.w;    //这个地方害我WA了6次;这错太隐蔽了!!!!。
    }
}edges[maxe];

int head[maxn];
vector<int> G[maxn];
int cnt;
int N,M,P;
double PT[maxn][maxn/2];
double dp[maxn][maxn/2];  //dp[i][j]表示以i为根、部署j个警察逮到robber的最大概率;


void addedge(int u,int v,int w){
    edges[cnt].assign(u,v,w,head[u]);
    head[u] = cnt++;
    edges[cnt].assign(v,u,w,head[v]);
    head[v] = cnt++;
}
void Dijkstra(){
    priority_queue<Edge>  Q;
    int d[maxn];
    bool vis[maxn];
    memset(d,0x3f,sizeof(d));
    memset(vis,0,sizeof(vis));
    for(int i=0;i<N;i++) G[i].clear();
    Q.push((Edge){0,0,0});
    d[0] = 0;
    while(!Q.empty()){
        Edge e = Q.top();  Q.pop();
        int u = e.u;
        if(vis[u]) continue;
        vis[u] = true;
        if(e.u != e.v){
            G[e.v].push_back(e.u);
        }
        for(int i=head[u];i!=-1;i=edges[i].next){
            int v = edges[i].v;
            if(d[v] > d[u] + edges[i].w){
                d[v] = d[u] + edges[i].w;
                Q.push((Edge){v,u,d[v]});  //把u存进去是为了方便建最短路图;
            }
        }
    }
}
void dfs(int u){
    int child = G[u].size();
    double son[maxn];                    //son[i]表示u的所有儿子节点总共部署i个人逮住robber的概率;
    for(int i=0;i<=P;i++)   son[i] = 0;
    if(child == 0){
        for(int i=1;i<=P;i++){
            dp[u][i] = PT[u][i];
        }
        return;
    }
    for(int i=0;i<child;i++){
        int v = G[u][i];
        dfs(v);                     // 求出了dp[v][...]的所有不同概率;
        for(int j=P;j>=0;j--)
          for(int k=0;k<=j;k++)
            son[j] = max(son[j],dp[v][k]/child+son[j-k]);  //u的v这个儿子及其子节点部署k个人的最大概率;
    }
    for(int i=P;i>=0;i--)         //总共i个人
      for(int j=0;j<=i;j++){      //u这个节点放j个人
        dp[u][i] = max(dp[u][i],PT[u][j] + (1-PT[u][j])* son[i-j]);
    }
}
int main()
{
    //freopen("E:\\acm\\input.txt","r",stdin);

    while(scanf("%d%d",&N,&M) == 2 && N+M){
        cnt = 0;
        memset(dp,0,sizeof(dp));
        memset(head,-1,sizeof(head));
        for(int i=1;i<=M;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            if(a == b) continue;
            addedge(a,b,c);
        }
        scanf("%d",&P);
        for(int i=0;i<N;i++)  PT[i][0] = 0;
        for(int i=0;i<N;i++)
            for(int j=1;j<=P;j++){
                scanf("%lf",&PT[i][j]);
            }
        Dijkstra();  //形成以0为根的最短路树;存在G[u]中;

        dfs(0);
        double ans = 0;
        for(int i=0;i<=P;i++)
            ans = max(ans,dp[0][i]);
        printf("%.2lf\n",ans*100);
    }
}

View Code

 

参考:http://www.cnblogs.com/acmdeweilai/archive/2013/08/10/3250515.html


  1. int half(int *array,int len,int key)
    {
    int l=0,r=len;
    while(l<r)
    {
    int m=(l+r)>>1;
    if(key>array )l=m+1;
    else if(key<array )r=m;
    else return m;
    }
    return -1;
    }
    这种就能避免一些Bug
    l,m,r
    左边是l,m;右边就是m+1,r;

  2. 第二块代码if(it != mp.end())应改为if(it != mp.end() && (i+1)!=(it->second +1));因为第二种解法如果数组有重复元素 就不正确