POJ 3311 Hie with the Pie(状压dp)

Description

The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. He will wait for 1 or more (up to 10) orders to be processed before he starts any deliveries. Needless to say, he would like to take the shortest route in delivering these goodies and returning to the pizzeria, even if it means passing the same location(s) or the pizzeria more than once on the way. He has commissioned you to write a program to help him.

Input

Input will consist of multiple test cases. The first line will contain a single integer n indicating the number of orders to deliver, where 1 ≤ n ≤ 10. After this will be n + 1 lines each containing n + 1 integers indicating the times to travel between the pizzeria (numbered 0) and the n locations (numbers 1 to n). The jth value on the ith line indicates the time to go directly from location i to location j without visiting any other locations along the way. Note that there may be quicker ways to go from i to j via other locations, due to different speed limits, traffic lights, etc. Also, the time values may not be symmetric, i.e., the time to go directly from location i to j may not be the same as the time to go directly from location j to i. An input value of n = 0 will terminate input.

Output

For each test case, you should output a single number indicating the minimum time to deliver all of the pizzas and return to the pizzeria.

Sample Input

3
0 1 10 10
1 0 1 2
10 1 0 10
10 2 10 0
0

Sample Output

8

大意:

比萨店以尽快向顾客提供比萨而自豪。不幸的是,由于裁员,他们只能雇一名司机来送货。在开始任何交付之前,他将等待处理1个或多个(最多10个)订单。不用说,他愿意走最短的路线运送这些货物并返回比萨店,即使这意味着在路上要经过同一地点或比萨店不止一次。他委托你写一个程序来帮助他。
Input
输入将由多个测试用例组成。第一行将包含一个整数n,表示要交付的订单数量,其中1≤ N≤ 10.之后是n+1行,每行包含n+1个整数,表示在比萨店(编号0)和n个地点(编号1到n)之间的旅行时间。第i行上的第j个值表示直接从位置i到位置j的时间,而不访问沿途的任何其他位置。请注意,由于不同的速度限制、交通灯等,从i到j可能有更快的方式通过其他位置。此外,时间值可能不是对称的,即直接从位置i到j的时间可能与直接从位置j到i的时间不同。输入值n=0将终止输入。
Output
对于每个测试用例,您应该输出一个数字,指示交付所有比萨和返回比萨店的最短时间。

思路1:

一开始想的就是用最短哈密顿路径那个题的思路来求,然后这里算上比萨店是n+1个点,他题目中说了在路上要金国同一个地点或比萨店不止一次,但是那个最短哈密顿路径的题是只经过一次,这个就有点拐弯了,就是说可以多次经过同一个点,那么咱们就只需要把每两个点之间的最短路径求出来,然后跑一遍最短哈密顿路径就行了,初始化很重要,一开始的f[1<<i][i]必须都设置成比萨店到i点的最短路,这个地方当时没想到,用了别的思路做出来的,至于为什么这么设置呢,可以看一下f[(1<<i)+1][0]这个状态的值一定是dis[0][i] + dis[i][0]的,所以这个f[1<<i][i]就可以设置成dis[0][i],最后输出dis[(1<<(i+1))-1][0]就行了,下面看代码

#include<iostream>
#include<cstring>
using namespace std;
const int N = 12;
typedef long long LL;
LL f[1<<N][N];
int g[N][N];
int main() {
	int n;
	while(cin>>n,n) {
		for(int i=0; i<=n; i++)
			for(int j=0; j<=n; j++)
				cin>>g[i][j];
		for(int i=0; i<1<<(n+1); i++)
			for(int j=0; j<=n; j++)
				f[i][j] = 1e9;
		for(int i=0;i<=n;i++)
			for(int j=0;j<=n;j++)
				for(int k=0;k<=n;k++)
					g[i][j] = min(g[i][j],g[i][k] + g[k][j]);
		for(int i=0;i<=n;i++) f[1<<i][i] = g[0][i]; 
		for(int i=0; i<1<<(n+1); i++)
			for(int j=0;j<=n;j++)
				if(i>>j&1) {
					for(int k=0; k<=n; k++)
						if((i-(1<<j))>>k&1) {
							f[i][j] = min(f[i-(1<<j)][k]+g[k][j],f[i][j]);
						}
				}
		cout<<f[(1<<(n+1))-1][0]<<endl;
	}
	return 0;
}

思路二

就是把比萨店到所有点的最短哈密顿路径求出来,最后枚举每个点把每个哈密顿通路都封装成哈密顿回路就行了,下面看代码

#include<iostream>
#include<cstring>
using namespace std;
const int N = 12;
typedef long long LL;
LL f[1<<N][N];
int g[N][N];
int main() {
	int n;
	while(cin>>n,n) {
		for(int i=0; i<=n; i++)
			for(int j=0; j<=n; j++)
				cin>>g[i][j];
		for(int i=0; i<1<<(n+1); i++)
			for(int j=0; j<=n; j++)
				f[i][j] = 1e9;
		f[1][0] = 0;
		for(int i=0;i<=n;i++)
			for(int j=0;j<=n;j++)
				for(int k=0;k<=n;k++)
					g[i][j] = min(g[i][j],g[i][k] + g[k][j]);
		for(int i=0; i<1<<(n+1); i++)
			for(int j=0;j<=n;j++)
				if(i>>j&1) {
					for(int k=0; k<=n; k++)
						if((i-(1<<j))>>k&1) {
							f[i][j] = min(f[i-(1<<j)][k]+g[k][j],f[i][j]);
						}
				}
		LL ans = 1e9;
		for(int i=0;i<=n;i++) ans = min(ans,f[(1<<(n+1))-1][i] + g[i][0]);
		cout<<ans<<endl;
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇智波一打七~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值