博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 4114 Disney's FastPass
阅读量:4457 次
发布时间:2019-06-08

本文共 2541 字,大约阅读时间需要 8 分钟。

状压dp+最短路。

一个无向图,接下来给出一些兴趣点,每个兴趣点被访问时有一定耗时。找一条从起点开始访问所有兴趣点再回到起点耗时最短的路(必须访问所有兴趣点,途中可以经过任意点(经过任意点包括兴趣点都不耗时),全程总耗时包括访问兴趣点和途经所有边)。每个兴趣点在一些点有通票,经过这些点中任意一个就可以拿到这个兴趣点的通票,拿到通票之后意味着访问这个兴趣点的耗时可以缩短。

题意比较复杂,给定的兴趣点的最大值是8。我们可以考虑用二进制来表示当前访问过的兴趣点以及当前拿到哪些兴趣点的通票,所以这两维状态的数量都是2^8=256种。每个点含有的通票都是来自兴趣点的,所以也用同样的状态表示方法来表示每个点含有哪些兴趣点的通票(在输入时完成)。

所谓状态转移,一个是当前状态可转移到哪些状态,另一个是可转移的状态的值怎么用当前状态的值来表示。dp[k][i][j]表示当前从起点走到k点(已获取k点含有的通票),拿到的通票的二进制状态的十进制表示为i,访问过的兴趣点的二进制状态的十进制表示为j,在此情况下的最短耗时。

可转移三种状态,一种是访问状态(转移到当前还没有访问过的兴趣点),一种是经过状态(转移到所有点(包括所有兴趣点)),一种是答案状态(如果当前状态已访问过所有兴趣点)。而对于新状态的值,从当前点到新点肯定要走最短路,需要预先floyd一遍。

因为访问兴趣点需要耗时,所以每个兴趣点只访问一次就好了(这与下句话并不冲突)。题目中说可能有多个兴趣点是同一个点,那么就要访问这个点多次,每次都当成一个兴趣点。

最后要注意的问题就是dp数组每一维的循环次序,可以把i,j当成同一组,对k的循环一定要在i,j的下层进行。为什么?因为当前状态完全可以转移到k更小的状态,但是转移到的状态的i,j的值一定不会减小。

#include 
#include
#include
#include
#include
#include
#include
using namespace std; // 传说中的状压dpconst int INF = 0x3F3F3F3F;const int MAXN = 51;int N, M, K, X;int g[MAXN][MAXN];int pos[8], T[8], FT[8];int pass[MAXN];int dp[MAXN][1 << 8][1 << 8];int ans;void init(){ memset(g, 0x3F, sizeof g); memset(pass, 0, sizeof pass); memset(dp, 0x3F, sizeof dp); for (int i = 1; i <= N; i++) g[i][i] = 0; ans = INF;}void floyd(){ for (int k = 1; k <= N; k++) { for (int i = 1; i <= N; i++) { for (int j = i + 1; j <= N; j++) { if (g[i][k] != INF && g[k][j] != INF && g[i][k] + g[k][j] < g[i][j]) { g[i][j] = g[j][i] = g[i][k] + g[k][j]; } } } }}void run(){ dp[1][0][0] = 0; // 初始状态 for (int i = 0; i < (1 << K); i++) { for (int j = 0; j < (1 << K); j++) { for (int k = 1; k <= N; k++) { int t = dp[k][i][j]; if (t != INF) { if (j == ((1 << K) - 1)) { ans = min(ans, t + g[k][1]); continue; } for (int n = 0; n < K; n++) // 1 { if (!(j&(1 << n)) && g[k][pos[n]] != INF) // 不加也行 { int& u = dp[pos[n]][i | pass[pos[n]]][j | (1 << n)]; u = min(u, t + g[k][pos[n]] + (i&(1 << n) ? FT[n] : T[n])); } } for (int n = 1; n <= N; n++) // 2 1,2部分可以调换位置,无影响 { if (g[k][n] != INF) // 不加也行 { int& u = dp[n][i | pass[n]][j]; u = min(u, t + g[k][n]); } } } } } }}int main(){ int a, b, c; scanf("%d", &X); for (int i = 1; i <= X; i++) { scanf("%d%d%d", &N, &M, &K); init(); for (int j = 0; j < M; j++) { scanf("%d%d%d", &a, &b, &c); g[a][b] = g[b][a] = c; } for (int j = 0; j < K; j++) { scanf("%d%d%d%d", &pos[j], &T[j], &FT[j], &a); for (; a--;) { scanf("%d", &b); pass[b] |= 1 << j; } } floyd(); run(); printf("Case #%d: %d\n", i, ans); } return 0;}

转载于:https://www.cnblogs.com/CrossingOver/p/10704840.html

你可能感兴趣的文章
BZOJ4723: [POI2017]Flappy Bird
查看>>
Spring Cloud
查看>>
Silverlight中打开文件和保存文件
查看>>
在自己认定的道路上顶着风雨坚持
查看>>
【Java集合源代码剖析】LinkedList源代码剖析
查看>>
php获取路径
查看>>
归并排序求逆序对
查看>>
总结:form中使用onSubmit="return false"防止表单自动提交,以及submit和button提交表单的区别...
查看>>
Javascript图片的懒加载与预加载
查看>>
ASP前台使用后台代码
查看>>
宏 CREATE_FUNC
查看>>
POJ1251 Kruskal
查看>>
欧拉计划之题目6:求1到100的平方和与和平方的差是多少?
查看>>
Java 回调机制
查看>>
struts2结合ajax实现无刷新登录
查看>>
Android笔记之Broadcast广播机制
查看>>
Git里.gitignore文件不起作用的解决
查看>>
eclipse 在复制/粘贴 时很卡(转)
查看>>
Android TableLayout官方文档 例子学习笔记
查看>>
分布式事务之:定期校对
查看>>