CH0103最短Hamilton路径 poj2288 Islands and Brigdes【状压DP】
虐狗宝典学习笔记:
取出整数\(n\)在二进制表示下的第\(k\)位 \((n >> k) & 1)\)
取出整数\(n\)在二进制表示下的第\(0 ~ k - 1\)位(后\(k\)位) \(n & ((1 << k) - 1)\)
把整数\(n\)在二进制表示下的第\(k\)位取反 \(n xor (1 << k)\)
对整数\(n\)在二进制表示下的第\(k\)为赋值\(1\) \(n | (1 << k)\)
对整数\(n\)在二进制表示下的第\(k\)位赋值\(0\) \(n & (~(1 << k))\)
CH0103---最短Hamilton路径
http://contest-hunter.org:83/contest/0x00%E3%80%8C%E5%9F%BA%E6%9C%AC%E7%AE%97%E6%B3%95%E3%80%8D%E4%BE%8B%E9%A2%98/0103%20%E6%9C%80%E7%9F%ADHamilton%E8%B7%AF%E5%BE%84
题意:
hamilton指的是每个节点经过一次且仅经过一次的路径。现在路径上有权值,问最短的路径长度。
思路:
状压dp。\(dp[i][j]\)表示在状态是\(i\)且最后一个经过的点时\(j\)时的最短路径长度。
\(dp[i][j] = min{dp[i xor (i << j)][k] + weight(k, j)}\)
1 #include <bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 using namespace std; 4 typedef long long LL; 5 6 int n; 7 int g[25][25]; 8 int dp[1 << 20][25]; 9 10 int main() 11 { 12 scanf("%d", &n); 13 memset(dp, 0x3f, sizeof(dp)); 14 for(int i = 0; i < n; i++){ 15 for(int j = 0; j < n; j++){ 16 scanf("%d", &g[i][j]); 17 } 18 } 19 dp[1][0] = 0; 20 for(int i = 1; i < 1 << n; i++){ 21 for(int j = 0; j < n; j++){ 22 if(i >> j & 1){ 23 for(int k = 0; k < n; k++){ 24 if((i ^ 1 << j) >> k & 1){ 25 dp[i][j] = min(dp[i][j], dp[i ^ 1 << j][k] + g[k][j]); 26 } 27 } 28 } 29 } 30 } 31 32 printf("%d\n", dp[(1 << n) - 1][n - 1]); 33 return 0; 34 }
poj2288---Islands and Bridges
http://poj.org/problem?id=2288
题意:
有n个岛,m座桥。每座岛有一个val,一条汉密尔顿路径的值是路径中所有点的val之和,加上所有路径上相邻的两个岛的val乘积之和,加上路径上相邻的三个岛的val乘积之和。求最大的值以及方案数。
思路:
和CH0103很相近,不同的是这道题要多存一个岛。\(dp[stat][i][j]\)表示当前状态是\(stat\),最后一个走的岛是\(j\),倒数第二个走的岛是\(i\), \(num\)数组表示对应的方案数。
当\( (stat, i, j) \)可达时,我们检查下一个要走的岛\(k\),如果此时\( (stat >> k) & 1 == 0 \) 且 \( g[j][k] == 1 \)说明\(k\)是满足条件的
设\(tmp\)是下一个走\(k\)时的总价值。那么,\(dp[stat | (1 << k)][j][k] = max(dp[stat | (1 << k)][j][k], tmp)\)
如果\(tmp == dp[stat | (1 << k)][j][k]\),那么,\(num[stat | (1 << k)][j][k] += num[stat][i][j]\)。否则\(num[stat | (1 << k)][j][k] = num[stat][i][j] \)
那么要如何求\(tmp\) 呢。
首先当\(j\)可以走到\(k\)时,肯定有 \(tmp = dp[stat][i][j] + val[k] + val[j] * val[k] \)
如果此时还有\(g[i][k] == 1\) 那么\(tmp += val[i] * val[j] * val[k]\)
最后我们对于\(stat = (1 << n) - 1\)枚举\(i\)和\(j\),找到最大的结果。
注意方案数会超出int。还需要注意\(n = 1\)时的特殊情况。
注意内存省着点,会MLE
1 //#include <bits/stdc++.h> 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 #include <cstring> 6 #include <stdio.h> 7 #include <vector> 8 #include <map> 9 #include <set> 10 #define inf 0x3f3f3f3f 11 using namespace std; 12 typedef long long LL; 13 14 int n, m, q; 15 bool g[13][13]; 16 int dp[1 << 13][13][13]; 17 LL num[1 << 13][13][13]; 18 int val[13]; 19 int cnt; 20 21 void hamilton() 22 { 23 memset(dp, -1, sizeof(dp)); 24 memset(num, 0, sizeof(num)); 25 for(int i = 0; i < n; i++){ 26 for(int j = 0; j < n; j++){ 27 if(g[i][j]){ 28 dp[1 << i | 1 << j][i][j] = val[i] + val[j] + val[i] * val[j]; 29 num[1 << i | 1 << j][i][j] = 1; 30 } 31 } 32 } 33 34 for(int stat = 1; stat < 1 << n; stat++){ 35 for(int i = 0; i < n; i++){ 36 if((stat >> i) & 1){ 37 for(int j = 0; j < n; j++){ 38 if((stat >> j) & 1){ 39 if(g[i][j] && dp[stat][i][j] != -1){ 40 for(int k = 0; k < n; k++){ 41 if(g[j][k] && k != i && ((stat >> k) & 1) == 0){ 42 int tmp = dp[stat][i][j] + val[k] + val[k] * val[j]; 43 if(g[i][k]){ 44 tmp += val[i] * val[j] * val[k]; 45 } 46 if(tmp > dp[stat | (1 << k)][j][k]){ 47 dp[stat | (1 << k)][j][k] = tmp; 48 num[stat | (1 << k)][j][k] = num[stat][i][j]; 49 } 50 else if(tmp == dp[stat | (1 << k)][j][k]){ 51 num[stat | (1 << k)][j][k] += num[stat][i][j]; 52 } 53 } 54 } 55 } 56 } 57 } 58 } 59 } 60 } 61 //return dp[(1 << n) - 1][n - 1]; 62 } 63 64 int main() 65 { 66 scanf("%d", &q); 67 while(q--){ 68 memset(g, 0, sizeof(g)); 69 scanf("%d%d", &n, &m); 70 for(int i = 0; i < n; i++){ 71 scanf("%d", &val[i]); 72 } 73 for(int i = 0; i < m; i++){ 74 int u, v; 75 scanf("%d%d", &u, &v); 76 g[u - 1][v - 1] = 1; 77 g[v - 1][u - 1] = 1; 78 } 79 if(n == 1){ 80 printf("%d 1\n", val[0]); 81 continue; 82 } 83 84 hamilton(); 85 int maxi = 0; 86 LL ans = 0; 87 for(int i = 0; i < n; i++){ 88 for(int j = 0; j < n; j++){ 89 if(g[i][j]){ 90 if(maxi < dp[(1 << n) - 1][i][j]){ 91 maxi = dp[(1 << n) - 1][i][j]; 92 ans = num[(1 << n) - 1][i][j]; 93 } 94 else if(maxi == dp[(1 << n) - 1][i][j]){ 95 ans += num[(1 << n) - 1][i][j]; 96 } 97 } 98 } 99 } 100 101 printf("%d %lld\n", maxi, ans / 2); 102 } 103 return 0; 104 }
转载于:https://www.cnblogs.com/wyboooo/p/9932142.html
CH0103最短Hamilton路径 poj2288 Islands and Brigdes【状压DP】相关推荐
- 最短Hamilton路径-状压dp解法
最短Hamilton路径 时间限制: 2 Sec 内存限制: 128 MB 题目描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamil ...
- 《算法竞赛进阶指南》打卡-基本算法-AcWing 91. 最短Hamilton路径:位运算、状态压缩dp、dp
文章目录 题目解答 题目链接 题目解答 分析: 状态压缩dp是用二进制数来表示状态. 数据范围n = 20, 那么状态总量就是2202^{20}220个状态. 可以按照以下思路去思考: 哪些点被用过 ...
- 最短Hamilton路径与旅行商问题联系与解决
最短Hamilton路径与旅行商问题 前言 最短Hamilton路径 旅行商问题 前言 发现很多篇博客都是要么直接贴代码,要么就对dp式子进行解释,没有说为什么得到这个式子就很让人感到无语,这可能就是 ...
- 最短Hamilton路径(状压dp)
链接:https://ac.nowcoder.com/acm/problem/50909 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言5242 ...
- 最短Hamilton路径
题目描述 给定一张 n 个点的带权无向图,点从 0 ~ n−1 标号,求起点 0 到终点 n−1 的最短 Hamilton 路径. Hamilton 路径的定义是从 0 到 n−1 不重不漏地经过每个 ...
- 最短Hamilton路径(位运算基本思路)
题目描述 给定一张 n 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次 ...
- 最短Hamilton路径(哈密顿图,状压dp)
题目: 给定一张 n 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次. ...
- 【动态规划】CH_0103 最短Hamilton路径
题意 给出一张 n ( n ≤ 20 ) n(n \leq 20) n(n≤20)个点的带权无向图,求出起点0到终点n-1的最短Hamilton路径. Hamilton路径的定义是从0到n-1不重不漏 ...
- [状压dp] 最短Hamilton路径(模板题+状压dp)
文章目录 0. 前言 1. 状压dp 模板题 0. 前言 状压 dp 就是采用二进制数保存状态,方便进行位运算操作.例如 八皇后.八数码问题也都是采用了状态压缩的思想来使用一个二进制数唯一对应集合中的 ...
最新文章
- phantomjs 抓取html,javascript – 如何使用PhantomJS获取网站的HTML源代码
- SQL Server技术问题之视图优缺点
- C++ Primer 5th笔记(chap 15 OOP)构造函数和拷贝控制
- 在caffe上fine-tuning网络
- python中if else语句_python 中if else 语句的作用及示例代码
- wincc客户机打开服务器文件通讯不上,wincc客户机连不上服务器
- 【POJ - 2378】Tree Cutting(树形dp,树的重心变形)
- sql2000下 分页存储过程(一)
- 公众号添加百度网盘链接
- 【科普向】5G核心网架构和关键技术
- 互联网日报 | 美团外卖日订单量突破4000万个;《王者荣耀》动画番剧启动;360金融更名为360数科...
- 拉昆塔温德姆酒店中国首店即将亮相山东潍坊;复星旅文旗下Club Med落子北美市场 | 全球旅报...
- java毕业生设计原创网络文学管理系统计算机源码+系统+mysql+调试部署+lw
- ubantu 16 nfs挂载
- 台式计算机快捷键大全,电脑常用快捷键有哪些
- 显著性目标检测SOD论文大盘点
- 考研数据结构之队列(3.3)——练习题之设计一个循环队列,用front和rear分别作为队头和队尾指针,另外用一个标志tag表示队列是空还是不空来设计队列的结构和相关基本运算算法(C表示)
- LeetCode 844 题解
- 什么双机热备? 为什么要做双机热备? 双机热备有哪几种?
- AAA 及RADIUS协议配置