POJ - 2686 Traveling by Stagecoach (状压dp)

POJ - 2686 Traveling by Stagecoach (状压dp)

题意

  有一个旅行家计划乘马车旅行,他所在的国家里共有m个城市,在城市之间有若干道路相连,从某个城市沿着某条道路到相邻城市需要乘坐马车。而乘坐马车需要使用车票,每用一张车票只可以通过一条道路。每张车票上都记有马的匹数,从一个城市移动到另一个城市的所需时间等于城市之间的道路的长度除以马的数量的结果。这位旅行家一共有n张车票,第i张车票上的马的匹数是ti,一张车票只能使用一次,并且换乘所需要的时间可以忽略。求从城市a到城市b所需要的最短时间。如果无法到达城市b就输出“Impossible”

思路

  dp[s][u]表示现在在城市u,此时剩下的车票的集合为s。从当前状态出发,使用一张车票i∈s移动到相邻城市v,就相当于转移到了“在城市v,此时还剩下的车票的集合为s{i}”这个状态,把这个状态转移看成一条边,边上花费就是(u-v的道路长度)/ti。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 30;
int n, m, p, a, b;
int t[MAXN];
const double inf = 10000000;
double dp[1 << 13][MAXN];
double d[MAXN][MAXN];
int mmm; 
int main() {
	while (scanf("%d%d%d%d%d", &n, &m, &p, &a, &b) != EOF) {
		if(!m && !n && !p && !a && !b)  break;
		a--,b--;
		memset(d, -1, sizeof(d));
		memset(t, 0, sizeof(t));
		for(int i = 0; i < n; i++)  scanf("%d", &t[i]);
		int u, v;
		double dis;
		for(int i = 0; i < p; i++) {
			scanf("%d%d%lf", &u, &v, &dis);
			u--,v--;
			d[u][v] = dis;
			d[v][u] = dis;
		}

		for(int i = 0; i < (1<<12)-1; i++) {
			for(int j = 0; j <= MAXN; j++) {
				dp[i][j] = inf;
			}
		}
		dp[(1<<n)-1][b] = 0;
		double res = inf;
		for(int s = (1<<n)-1; s>=0; s--) {
			for(int i = 0; i<n; i++) {
				if(s>>i&1) {
					for(int u =0; u<m; u++) {
						for(int v=0; v<m; v++) {
							if(d[u][v]>=0) {
								dp[s][v] = min(dp[s][v], dp[s&~(1<<i)][u] + (double)d[u][v] / (double)t[i]);
							}
						}
					}
				}
			}
			res = min(res,dp[s][b]);
		}
		if(res >= inf)printf("Impossible\n");
		else printf("%.3f\n", res);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值