hdu 4568 Hunter 最短路+dp

Hunter

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2014    Accepted Submission(s): 615

Problem Description

  One day, a hunter named James went to a mysterious area to find the treasures. James wanted to research the area and brought all treasures that he could.
  The area can be represented as a N*M rectangle. Any points of the rectangle is a number means the cost of research it,-1 means James can‘t cross it, James can start at any place out of the rectangle, and explore point next by next. He will move in the rectangle and bring out all treasures he can take. Of course, he will end at any border to go out of rectangle(James will research every point at anytime he cross because he can‘t remember whether the point are researched or not).
  Now give you a map of the area, you must calculate the least cost that James bring out all treasures he can take(one point up to only one treasure).Also, if nothing James can get, please output 0.

Input

  The input consists of T test cases. The number of test cases T is given in the first line of the input. Each test case begins with a line containing 2 integers N M , (1<=N,M<=200), that represents the rectangle. Each of the following N lines contains M numbers(0~9),represent the cost of each point. Next is K(1<=K<=13),and next K lines, each line contains 2 integers x y means the position of the treasures, x means row and start from 0, y means column start from 0 too.

Output

  For each test case, you should output only a number means the minimum cost.

Sample Input

2

3 3

3 2 3

5 4 3

1 4 2

1

1 1

3 3

3 2 3

5 4 3

1 4 2

2

1 1

2 2

Sample Output

8
11

/*
hdu 4568 Hunter 最短路+dp

problem:
给你一个n*m的地图,每走一个格子会有一定的花费.求拿到所有宝藏的最小花费

solve:
想了很久感觉没什么思路TAT
后来看别人题解可以把这个问题转换一下.
因为总共只有13个宝藏,所以我们可以处理出每个宝藏之间的最短路(即最小花费).
在弄出每个宝藏到边界的最小距离. 那么就可以看成13个点的图.找出遍历所有点的最小花费
而13个点的状态可以用二进制保存,所以dp就好.

hhh-2016-08-26 21:43:38
*/
#pragma comment(linker,"/STACK:124000000,124000000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <math.h>
#include <queue>
#include <map>
#define lson  i<<1
#define rson  i<<1|1
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define scanfi(a) scanf("%d",&a)
#define scanfl(a) scanf("%I64d",&a)
#define key_val ch[ch[root][1]][0]
#define inf 0x3f3f3f3f
using namespace std;
const ll mod = 1e9+7;
const int maxn = 220;

struct NODE
{
    int id,len;
    NODE() {}
    NODE(int i,int d):id(i),len(d) {}
    bool operator <(const NODE &a) const
    {
        return len >  a.len;
    }
};
int n,m;
int dx[4]= {-1,1,0,0};
int dy[4]= {0,0,-1,1};
int from[maxn][maxn];
int vis[maxn*maxn],tmap[maxn][maxn],tp[maxn][maxn],out[maxn];
int pos[maxn*maxn],dis[maxn*maxn];
void dij(int st,int fp)
{
    memset(vis,0,sizeof(vis));
    memset(dis,inf,sizeof(dis));
    priority_queue<NODE> q;
    q.push(NODE(st,0));
    dis[st] = 0;
    while(!q.empty())
    {
        NODE t = q.top();
        q.pop();
        int cur = t.id;
        if(vis[cur]) continue;
        vis[cur] = 1;
        int x = cur/m,y = cur%m;
        if(tp[x][y] != -1)
            from[fp][tp[x][y]] = dis[cur];
        if(x == n-1 || x == 0 || y == m-1 || y == 0)
        {
            out[fp]= min(out[fp],dis[cur]);
        }
        for(int i = 0; i < 4; i++)
        {
            int tx = x + dx[i];
            int ty = y + dy[i];
            if(tmap[tx][ty] == -1) continue;
            if(tx >= n || tx < 0 || ty >= m || ty < 0)
                continue;
            if(dis[tx*m + ty] > dis[cur] + tmap[tx][ty])
            {
                dis[tx*m + ty] = dis[cur] + tmap[tx][ty];
                q.push(NODE(tx*m + ty, dis[tx*m + ty] ));
            }
        }
    }
    return ;
}

int dp[20][1 << 14];
void init()
{
    memset(from,0,sizeof(from));
    memset(out,inf,sizeof(out));
    memset(tp,-1,sizeof(tp));
    memset(dp,inf,sizeof(dp));
}

int main()
{
//    freopen("in.txt","r",stdin);
    int T,x,y;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanfi(n),scanfi(m);
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < m; j++)
                scanfi(tmap[i][j]);
        }
        int q;
        scanfi(q);
        for(int i = 0; i < q; i++)
        {
            scanfi(x),scanfi(y);
            tp[x][y] = i;
            pos[i] = x*m + y;
        }
        for(int i = 0; i < q; i++)
        {
            from[i][i] = 0;
            dij(pos[i],i);
        }
        for(int i = 0; i < q; i++)
        {
            dp[i][1 << i] = out[i]+tmap[pos[i]/m][pos[i]%m];
        }
//        for(int i = 0;i < q;i++)
//        {
//            cout << "i"<<i<<":" <<out[i] <<endl;
//            for(int j = i;j < q;j++)
//                cout << i <<"----"<<j<<" :" <<from[i][j]<<endl;
//        }
//        cout <<endl;
        for(int i = 0; i < (1 << q); i++)
        {
            for(int j = 0; j < q; j++)
            {
                if( ((1 << j) & i) && i != (1 << j))
                {
                    for(int k = 0; k < q; k++)
                    {
                        if( (i & (1 << k)) && j != k && i != (1<< k))
                            dp[j][i] = min(dp[k][i-(1 << j)]+from[k][j],dp[j][i]);
                    }
                }
            }
        }
        int ans = inf;
        for(int i = 0; i < q; i++)
        {
            ans = min(ans,dp[i][(1<<q)-1] + out[i]);
//            cout << ans <<endl;
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

时间: 2024-12-06 11:32:11

hdu 4568 Hunter 最短路+dp的相关文章

HDU 4568 Hunter 最短路+状压DP

题意:给一个n*m的格子,格子中有一些数,如果是正整数则为到此格子的花费,如果为-1表示此格子不可到,现在给k个宝藏的地点(k<=13),求一个人从边界外一点进入整个棋盘,然后拿走所有能拿走的宝藏的最小花费,如果一次不能拿走所有能拿到的或者根本拿不到任何宝藏,输出0. 解法:看到k的范围应该想到状态压缩,将每个格子都看成一个点,再新建两个点,一个表示边界外的起点,用0表示,一个表示边界外的终点,用n*m+1表示,然后相互建边,建有向边,边权为终点格子的花费值,(其实都不用建边,直接跑最短路也行)

hdu 4568 spfa 最短路算法+旅行商问题

http://acm.hdu.edu.cn/showproblem.php?pid=4568 Problem Description One day, a hunter named James went to a mysterious area to find the treasures. James wanted to research the area and brought all treasures that he could. The area can be represented a

hdu 4568(状态压缩dp)

题意:一张n*m的网格内每个点有话费,还有若干个宝藏,问一个人要走进去拿走所有宝藏在走出来的最小花费. 思路:看宝藏只有13个直接想到了状压dp[i][j]拿了哪几个前一个为j的最小花费,先bfs+优先队列预处理出最短路,然后记忆化搜索就可. 代码如下: 1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao

hdu 4568 bfs + 状压dp

//这题的数据是不是有问题... 不考虑宝藏一个也拿不到也能AC... 1 #include "bits/stdc++.h" 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 int T; 5 int N, M; 6 int mat[210][210]; 7 int K; 8 int tot_tra, tra[210][210]; 9 10 //dp parameters 11 int dis_tra_broder[20],

HDU 4284Travel(状压DP)

HDU 4284    Travel 有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1走完所有的他必须要去的城市,打完所有的工,并且成功回到起点1 由于H<=15,所以显然可以状压,预处理这些都必须去的城市之间的最短距离(可以floyd),然后状压DP[S][i]表示他到达了S这些城市后正处在第i个城市里(所以S & (1<<i) != 0)的剩余的最大的钱的数量,然

hdu 3555 Bomb(数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555 题目大意:就是给你一个数n,判断从0到n有多少个数含有数字49...... 是不是觉得跟hdu2089很相似呀... 思路:跟hdu2089一样的,注意给出的数比较大,所以这儿用__int64  .... code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm&

HDU 1231 最大连续子序列 DP题解

典型的DP题目,增加一个额外要求,输出子序列的开始和结尾的数值. 增加一个记录方法,nothing special. 记录最终ans的时候,同时记录开始和结尾下标: 更新当前最大值sum的时候,更新开始节点. const int MAX_N = 10001; long long arr[MAX_N]; int N, sta, end; long long getMaxSubs() { long long sum = 0, ans = LLONG_MIN; int ts = 0; for (int

[ACM] hdu 2089 不要62(数位Dp)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 19043    Accepted Submission(s): 6442 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就

HDU 4901 The Romantic Hero(DP)

HDU 4901 The Romantic Hero 题目链接 题意:给定一个序列,要求找一个分界点,然后左边选一些数异或和,和右边选一些数且和相等,问有几种方法 思路:dp,从左往右和从右往左dp,求出异或和且的个数,然后找一个分界点,使得一边必须在分界点上,一边随意,然后根据乘法原理和加法原理计算 代码: #include <cstdio> #include <cstring> typedef __int64 ll; const int N = 1024; const int