最优配对问题(集合上的动态规划) —— 状压DP
题目来源:紫书P284
题意:
给出n个点的空间坐标(n为偶数, n<=20), 把他们配成n/2对, 问:怎样配对才能使点对的距离和最小?
题解:
设dp[s]为:状态为s(s代表着某个子集)时, 它的最小距离和。
1.对于一个状态s, 首先要计算它减少两个点后的状态的最小距离和, 然后当前状态才能从这些状态中转移过来。
2.如何转移:对于状态s, 在集合中随便找一个点,枚举集合中的其他点与它配对, 取距离和最小的那一对。
3.为什么选定一个点,然后枚举集合中的其他点就可以呢?而两个点都要枚举呢? 因为:对于选定的点, 它总得要和集合中的其他点配对, 那么答案就肯定蕴藏在某一次配对中了。而枚举两个点, 实际上是多余的。
实现:
1.递推:自底向上,从最小的子集开始计算, 然后大的子集就可以从中转移过来。缺点是点数为奇数的情况也考虑进去了(可以预先判断点数是否为偶,以决定是否需要进入 计算), 速度慢。
2.记忆化搜索:很好理解,对于状态s, 假设它的偶数子集的最小距离和都计算出来了, 那么选定某个点, 再枚举其他点就可以了。而且避免了奇数个元素的子集的计算。
递推:
- #include <iostream>
- #include <cstdio>
- #include <cmath>
- using namespace std;
- const int INF = 2e9;
- const int maxn = 21;
- struct Node{
- double x, y, z;
- }dot[maxn];
- int n;
- double dp[1<<maxn+1];
- double dis(Node a, Node b)
- {
- return sqrt( (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y) + (a.z - b.z)*(a.z - b.z) );
- }
- void solve()
- {
- dp[0] = 0;
- for(int i = 1; i<(1<<n); i++)
- dp[i] = INF;
- for(int s = 1; s < (1 << n); s++)
- {
- int i;
- for(i = 0; i<n; i++)
- if(s&(1<<i)) break;
- for(int j = i+1; j<n; j++)
- if(s&(1<<j))
- dp[s] = min(dp[s], dis(dot[i], dot[j]) + dp[s^(1<<i)^(1<<j)]);
- }
- }
- int main()
- {
- cin >> n;
- for(int i = 0; i < n; i++)
- cin >> dot[i].x >> dot[i].y >> dot[i].z;
- solve();
- cout << dp[(1<<n) - 1] << endl;
- }
记忆化搜索:
- #include <iostream>
- #include <cstdio>
- #include <cmath>
- using namespace std;
- const int INF = 2e9;
- const int maxn = 21;
- struct Node{
- double x, y, z;
- }dot[maxn];
- int n;
- double dp[1<<maxn];
- double dis(Node a, Node b)
- {
- return sqrt( (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y) + (a.z - b.z)*(a.z - b.z) );
- }
- double dfs(int s)
- {
- if(dp[s] != INF)
- return dp[s];
- int i;
- for(i = 0; i<n; i++)
- if(s&(1<<i)) break;
- for(int j = i+1; j<n; j++)
- if(s&(1<<j))
- dp[s] = min( dp[s], dis(dot[i], dot[j]) + dfs(s^(1<<i)^(1<<j)) );
- return dp[s];
- }
- int main()
- {
- cin >> n;
- for(int i = 0; i < n; i++)
- cin >> dot[i].x >> dot[i].y >> dot[i].z;
- dp[0] = 0;
- for(int i = 1; i < (1<<n); i++)
- dp[i] = INF;
- cout << dfs((1<<n) - 1) << endl;
- }
最优配对问题(集合上的动态规划) —— 状压DP的更多相关文章
- 状态压缩动态规划 状压DP
总述 状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式 很多棋盘问题都运用到了状压,同时,状压也很经常和BFS及DP连用,例题里会给出介绍 有了状态,DP就比 ...
- 动态规划---状压dp
状压dp,就是把动态规划之中的一个个状态用二进制表示,主要运用位运算. 这里有一道例题:蓝书P639猛兽军团1 [SCOI2005]互不侵犯 题目: 题目描述 在N×N的棋盘里面放K个国王,使他们互不 ...
- 状态压缩动态规划(状压DP)详解
0 引子 不要999,也不要888,只要288,只要288,状压DP带回家.你买不了上当,买不了欺骗.它可以当搜索,也可以卡常数,还可以装B,方式多样,随心搭配,自由多变,一定符合你的口味! 在计算机 ...
- [HNOI2012]集合选数(状压DP+构造)
题目要求若出现x,则不能出现2x,3x 所以我们考虑构造一个矩阵 \(1\ 2\ 4 \ 8--\) \(3\ 6\ 12\ 24--\) \(9\ 18\ 36--\) \(--\) 不难发现,对于 ...
- B - 集合选数 (状压DP)
题目链接:https://cn.vjudge.net/contest/281960#problem/B 题目大意:中文题目 具体思路: 我们通过构造矩阵, x , 3x,9x,27x 2x,6x,18 ...
- BZOJ2734 HNOI2012集合选数(状压dp)
完全想不到的第一步是构造一个矩阵,使得每行构成公比为3的等比数列,每列构成公比为2的等比数列.显然矩阵左上角的数决定了这个矩阵,只要其取遍所有既不被2也不被3整除的数那么所得矩阵的并就是所有的数了,并 ...
- BZOJ3724 [HNOI2012]集合选数 【状压dp】
题目链接 BZOJ3724 题解 构造矩阵的思路真的没想到 选\(x\)就不能选\(2x\)和\(3x\),会发现实际可以转化为矩阵相邻两项 \[\begin{matrix}1 & 3 &am ...
- BZOJ 2734 洛谷 3226 [HNOI2012]集合选数【状压DP】【思维题】
[题解] 思维题,看了别人的博客才会写. 写出这样的矩阵: 1,3,9,... 2,6,18,... 4,12.36,... 8,24,72,... 我们要做的就是从矩阵中选出一些数字,但是不能选相邻 ...
- bzoj2734:[HNOI2012]集合选数(状压DP)
菜菜的喵喵题~ 化序列为矩阵!化腐朽为神奇!左上角为1,往右每次*3,往下每次*2,这样子就把问题转化成了在矩阵里选不相邻的数有几种可能. 举个矩阵的例子 1 3 9 27 2 6 18 54 4 1 ...
- 多米诺骨牌放置问题(状压DP)
例题: 最近小A遇到了一个很有趣的问题: 现在有一个\(n\times m\)规格的桌面,我们希望用\(1 \times 2\)规格的多米诺骨牌将其覆盖. 例如,对于一个\(10 \times 11\ ...
随机推荐
- k8s之nginx-ingress、 Daemonset实现生产案例
上一篇中用node ip + 非80端口,访问k8s集群内部的服务.实际生产中更希望用node ip + 80端口的方式,访问k8s集群内的服务. # 修改mandatory.yaml中创建控制器部分 ...
- Codeforces Gym 100203I I WIN 最大流
原题链接:http://codeforces.com/gym/100203/attachments/download/1702/statements.pdf 题解 首先寻找每个I,然后枚举形状,如果匹 ...
- ruti
也许我可以说除了我把+号写成了-号这个程序几乎是完美的
- eclipse主题下载网站
http://eclipsecolorthemes.org/
- 提交IOS开发效率的几个插件(Xcode神器推荐贴)
Code Pilot 2 Xcode上的Command-T,讓你快速跳轉到某個文件或某個符號 XVim 讓Xcode使用Vim的鍵綁定,Vim党必備 Injection for Xcode 調試利器, ...
- dll的使用
2016-12-11 23:02:24 一:生成DLL 1:创建DLL工程 文件->新建->项目->visual c++->win32->win32控制台应用程序(w ...
- STL中各容器之函数总结
一.序列和关联非共同拥有函数 全部标准库共同拥有函数 (构造,相关属性,迭代器,插入与删除,比較.swap) 当中operator>,operator>=,operator<,op ...
- 怎样把多个Android Project打包成一个APK
怎样把多个Android Project打包成一个APK(你的项目怎样引用其它项目). 怎样把多个android project 打包成一个apk呢,事实上原理是这种.一个主project引用其它的p ...
- 2013-06-09 12:03 如何在SQLServer中锁定某行记录
锁的概述 一. 为什么要引入锁 多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: 丢失更新 A,B两个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果,比如订 ...
- asp .net 为图片添加图片水印 .
首先写好一个写入图片水印的类,先创建一个ImageWriter类库 (该类中有包含枚举类型和方法) using System; using System.Collections.Generic; ...