Harry And Dig Machine HDU - 5067 (状压DP,TSP(旅行商)问题)

Harry And Dig Machine

 题目链接:HDU - 5067 

题意:n*m的矩阵中有n(n<=10)个数字大于0的格子,从左上角即(0, 0)点开始,要求便利所有数字大于0的格子并最终返回(0, 0),每移动一步消耗一点体力,且只能上下左右移动,问最少消耗的体力;

思路:刚拿到这个题毫无头绪,搜了下题解,才知道这是一道TSP(旅行商)的经典题目;(以下来自百度百科)

旅行商问题(TravelingSalesmanProblem,TSP)是一个经典的组合优化问题。经典的TSP可以描述为:一个商品推销员要去若干个城市推销商品,该推销员从一个城市出发,需要经过所有城市后,回到出发地。应如何选择行进路线,以使总的行程最短。从图论的角度来看,该问题实质是在一个带权完全无向图中,找一个权值最小的Hamilton回路。

用二进制的0,1表示是否走过某一点,进行状态压缩;

再看这道题,最多有11个点,,哎,不是10个吗,注意,起点也算是一个点!!!

相当于是11位的二进制,最大为(1<<12)-1;dp[i][j]表示为在i状态下最终到达j点消耗的最小体力,那么初始状态是由(0, 0)点(编号为1)到i点消耗dis(1, i)体力;最终状态是(1<<n)-1状态下最终到达1点(n表示共有n个点);

状态转移方程:dp[i][j]=min(dp[i][j], dp[i-(1<<(j-1))][k]+dis(j, k));  

上式表示i状态下最终到达j点可以由先到达k点再到达j点转移过来,需要注意的事i状态中,必须已经有了j, k两点,即:i&(1<<(j-1))!=0 ,   1&(1<<(k-1))!=0;

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
struct node{
	int x, y;
	node(){}
	node(int x0, int y0){
		x=x0, y=y0;
	}
}point[15];
int dp[1<<12][15];
int dis(int i, int j){
	return abs(point[i].x-point[j].x)+abs(point[i].y-point[j].y);
}
int main(){
	int n, m;
	while(~scanf("%d%d", &n, &m)){
		int cnt=0;
		for(int i=0; i<n; i++){
			for(int j=0; j<m; j++){
				int x;
				scanf("%d", &x);
				if(i==0&&j==0){
					point[++cnt]=node(i, j);
				}
				else if(x>0){
					point[++cnt]=node(i, j);
				}
			} 
		}
		if(cnt==1){//注意特殊情况的判断,只有一个点不需要移动;
			printf("0\n");
			continue;
		}
		memset(dp, INF, sizeof(dp));
		for(int i=2; i<=cnt; i++){
			dp[1<<(i-1)][i]=dis(1, i);
		}
		for(int i=1; i<(1<<cnt); i++){
			for(int j=1; j<=cnt; j++){
				if(i&(1<<(j-1))){
					for(int k=1; k<=cnt; k++){
						if(j==k) continue;
						if(i&(1<<(k-1))){
							dp[i][j]=min(dp[i][j], dp[i-(1<<(j-1))][k]+dis(k, j));
						}
					}
				}
			}
		}
		printf("%d\n", dp[(1<<cnt)-1][1]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/81362676
dig