题目链接:http://poj.org/problem?id=2686
思路:
dp【二进制表示剩下的票】【v】;
假设票有3张,那么最初始的状态是 dp[ 111 ] [ a ] = 0;尝试在三张中拿一张,然后从a点出发到所有能到的点,由此更新状态;
拿票的二进制操作时 S & ~(1 << i) , 把二进制数S中 第j个数变为0; 查看二进制数S第j个数是否是0的操作:(S & (1<<j)) > 0,要注意最外面的那个括号,因为这个括号卡了很久!!!!
还有要注意的是,最少的时间未必一定能把票用完,所以要把所有可能的情况,哪怕票还有都要查看一遍,选时间最少的那个;
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const double INF = 1e8;
double dp[1<<10][40];
int t[20], G[40][40];
int main (void)
{
int n, m, p, a, b;
while (scanf ("%d%d%d%d%d", &n, &m, &p, &a, &b) != EOF) {
if (!n && !m && !p && !a && !b) break;
for (int i = 0; i < n; ++i) scanf ("%d", &t[i]);
memset (G, -1, sizeof (G));
int u, v, w;
for (int i = 0; i < p; ++i) {
scanf ("%d%d%d", &u, &v, &w);
G[u][v] = G[v][u] = w;
}
for (int i = 0; i < 1<<n; ++i)
fill (dp[i], dp[i]+m+1, INF);
dp[(1<<n)-1][a] = 0;
double ans = INF;
for (int i = (1<<n)-1; i >= 0; --i) {
ans = min (dp[i][b], ans);
for (int v = 1; v <= m; ++v) {
for (int j = 0; j < n; ++j) {
if (i & (1<<j)) {
for (int u = 1; u <= m; ++u) {
if (G[u][v] >= 0 ) {
dp[i & ~(1<<j)][u] = min (dp[i & ~(1<<j)][u], dp[i][v] + (double)G[u][v]/t[j]);
}
}
}
}
}
}
if (ans >= INF) printf ("Impossible\n");
else printf ("%.3f\n", ans);
}
return 0;
}
本文详细解析了POJ 2686题目的解题思路,采用动态规划结合图论的方法,通过二进制表示剩余票数状态,实现从任意点出发到所有可达点的最短时间计算,同时考虑了可能未完全使用票数的情况。
2359

被折叠的 条评论
为什么被折叠?



