题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4568

题目大意:

给一个矩阵 n*m (n m<=200),方格里如果是0~9表示通过它时要花费的代价,-1表示不能通过它。

矩阵中有k(k<=13)个珠宝,问从任意外边框出发取走所有珠宝并求走出矩阵的最小的代价。

解题思路:

先dij预处理每一个珠宝到其他其他珠宝的最小花费,不包括自己的花费。然后就是裸的TSP问题了,状态压缩dp即可。

dp[i][j]表示最后到达第i个珠宝,且访问珠宝的状态为j时,最小的花费。

dd[i][j]表示珠宝i到珠宝j之间的花费,注意此时包括j的花费不包括i的花费。

对于已求出的每一种珠宝状态更新后面未求出珠宝的状态。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std; /*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
struct Node
{
int id,dis;
//Node(){}
Node(int x,int y)
{
id=x,dis=y;
}
friend bool operator <(const struct Node &a,const struct Node &b)
{
return a.dis>b.dis; //按距离从小到达排序,便于优先队列找到距离当前宝藏的最小距离
}
};
#define Maxn 220
int dd[20][20];//两个宝藏之间的距离
int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
int istr[Maxn][Maxn]; //表示珠宝的标号
int sa[Maxn][Maxn],cost[20];//cost[i]表示i宝藏到边界的最短距离
int n,m,k,hash[20],dp[20][1<<15]; int tmpdis[Maxn*Maxn];//其他宝藏距离当前宝藏的距离
bool vis[Maxn][Maxn]; bool isbor(int x,int y) //是否为边界
{
if(x==0||x==n-1||y==0||y==m-1)
return true;
return false;
} bool iscan(int x,int y) //是否在矩阵内部
{
if(x<0||x>=n||y<0||y>=m)
return false;
return true;
} void dij(int hh,int cur) //迪杰斯特拉算法求
{
memset(tmpdis,INF,sizeof(tmpdis));
memset(vis,false,sizeof(vis));
vis[hh/m][hh%m]=true; priority_queue<Node>myq;
tmpdis[hh]=0;
myq.push(Node(hh,0)); while(!myq.empty())
{
Node tmp=myq.top(); //把距离当前宝藏距离最小的位置找到
myq.pop(); int tt=tmp.id;
int x=tt/m,y=tt%m; if(isbor(x,y)) //如果是边界,更新边界
cost[cur]=min(cost[cur],tmp.dis);
if(istr[x][y]!=-1) //如果是其他珠宝,更新两珠宝之间的距离
dd[cur][istr[x][y]]=tmp.dis;
for(int i=0;i<4;i++) //能走
{
int xx=x+dir[i][0],yy=y+dir[i][1];
if(!iscan(xx,yy)||vis[xx][yy])
continue;
if(sa[xx][yy]==-1)
continue;
vis[xx][yy]=true;
int temp=xx*m+yy;
tmpdis[temp]=min(tmpdis[temp],tmp.dis+sa[xx][yy]);
myq.push(Node(temp,tmpdis[temp])); }
}
}
int main()
{
int t,a,b; scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&sa[i][j]);
scanf("%d",&k);
memset(istr,-1,sizeof(istr));
for(int i=0;i<k;i++)
{
scanf("%d%d",&a,&b);
istr[a][b]=i;
hash[i]=a*m+b; //将坐标从二维转化成一维便于处理
}
memset(dd,INF,sizeof(dd));
for(int i=0;i<k;i++) //求出每一个宝藏到其他宝藏的距离
{
cost[i]=INF;
dd[i][i]=0; //宝藏从自己到自己距离为0
dij(hash[i],i); //找到从i到所有的宝藏的最短距离
//printf("i:%d cost:%d\n",i,cost[i]);
}
memset(dp,INF,sizeof(dp));
for(int i=0;i<k;i++)
{ //dp[i][1<<i]是包括i本身花费的,+进来花费cost[i]
dp[i][1<<i]=cost[i]+sa[hash[i]/m][hash[i]%m];
// printf("i:%d dp[i][1<<i]:%d\n",i,dp[i][1<<i]);
}
int lim=1<<k;
for(int i=0;i<lim;i++)
{
for(int j=0;j<k;j++)
{
if(!(i&(1<<j))) //如果没有经过第j个珠宝
continue;
if(dp[j][i]==INF) //此状态无效
continue;
for(int p=0;p<k;p++)
{
if(i&(1<<p)) //p没有经过
continue;
if(dd[j][p]==INF)
continue; //最后经过的变成了p 依据j->p 更新后面的状态
dp[p][i|(1<<p)]=min(dp[p][i|(1<<p)],dp[j][i]+dd[j][p]);
}//dp[j][i]是已经求得的状态了
}
}
int ans=INF;
for(int i=0;i<k;i++)
{
// printf("%d %d\n",i,dp[i][lim-1]);
ans=min(ans,dp[i][lim-1]+cost[i]); //从最短路走出去
} printf("%d\n",ans); } return 0;
}

最短路+状态压缩dp(旅行商问题)hdu-4568-Hunter的更多相关文章

  1. Light OJ 1316 A Wedding Party 最短路+状态压缩DP

    题目来源:Light OJ 1316 1316 - A Wedding Party 题意:和HDU 4284 差点儿相同 有一些商店 从起点到终点在走过尽量多商店的情况下求最短路 思路:首先预处理每两 ...

  2. 【状态压缩DP】HDU 4352 XHXJ'S LIS

    题目大意 Vjudge链接 定义一个数的内部LIS长度表示这个数每个数位构成的序列的LIS长度,给出区间\([l,r]\),求区间内内部LIS长度为\(k\)的数的个数. 输入格式 第一行给出数据组数 ...

  3. HDU 4511 (AC自动机+状态压缩DP)

    题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4511 题目大意:从1走到N,中间可以选择性经过某些点,比如1->N,或1->2-> ...

  4. HDU 3681 Prison Break(状态压缩dp + BFS)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681 前些天花时间看到的题目,但写出不来,弱弱的放弃了.没想到现在学弟居然写出这种代码来,大吃一惊附加 ...

  5. hdu 4568 Hunter 最短路+dp

    Hunter Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  6. HDU 1074 (状态压缩DP)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1074 题目大意:有N个作业(N<=15),每个作业需耗时,有一个截止期限.超期多少天就要扣多少 ...

  7. hdu 5025 Saving Tang Monk 状态压缩dp+广搜

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4092939.html 题目链接:hdu 5025 Saving Tang Monk 状态压缩 ...

  8. hdu 5094 Maze 状态压缩dp+广搜

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4092176.html 题目链接:hdu 5094 Maze 状态压缩dp+广搜 使用广度优先 ...

  9. hdu 4057 AC自己主动机+状态压缩dp

    http://acm.hdu.edu.cn/showproblem.php?pid=4057 Problem Description Dr. X is a biologist, who likes r ...

随机推荐

  1. Tornado(二)

    跨站请求伪造CSRF 开启xsrf(就是叫法不一样和csrf一样),'xsrf_cookies':True settings = { 'template_path':'template', 'stat ...

  2. BZOJ1064 NOI2008假面舞会

    挺神的这题,发现只有环和链两种情况 搜索时我们只考虑环的,因为链可以看成找不到分类的环. 当成链时大小是的最大值是各链长的和,最小值是3 当成环时最大值是各环长的gcd,最小值是大于3的最小的ans的 ...

  3. Problem G: 深入浅出学算法008-求佩尔方程的解

    Description 求关于x y的二次不定方程的解 x2-ny2=1 Input 多组输入数据,先输入组数T 然后输入正整数n(n<=100) Output 对于每组数据输出一行,求y< ...

  4. Problem B: 深入浅出学算法003-计算复杂度

    Description 算法复杂度一般分为:时间复杂度.空间复杂度.编程复杂度. 这三个复杂度本身是矛盾体,不能一味地追求降低某一复杂度,否则会带来其他复杂度的增加.在权衡各方面的情况下,降低时间复杂 ...

  5. Rails -- 关于Migration

    Rails -- 关于Migration 无聊去逛博客,发现一篇介绍Migration,挺详细的,留个链接,以后需要的时候看. 链接: http://www.cnblogs.com/orez88/ar ...

  6. Mysql -- 设置中国时区时间

       Mysql -- 设置中国时区时间 查看mysql的时区设置 mysql> show variables like '%time_zone%'; 修改mysql的时区设置, 注:mysql ...

  7. codeforces 148E Aragorn's Story 背包DP

    Aragorn's Story Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/probl ...

  8. PAT甲级1021. Deepest Root

    PAT甲级1021. Deepest Root 题意: 连接和非循环的图可以被认为是一棵树.树的高度取决于所选的根.现在你应该找到导致最高树的根.这样的根称为最深根. 输入规格: 每个输入文件包含一个 ...

  9. leetcode76. Minimum Window Substring

    leetcode76. Minimum Window Substring 题意: 给定字符串S和字符串T,找到S中的最小窗口,其中将包含复杂度O(n)中T中的所有字符. 例如, S ="AD ...

  10. 请不要乱用Kotlin ? 空检查

    直接上实例: fun main(args: Array<String>) { println("now, begin save data to database") v ...