集合上的动态规划---最优配对问题(推荐:*****) // uva 10911
- /*
- 提醒推荐:五星
- 刘汝佳《算法竞赛入门经典》,集合上的动态规划---最优配对问题
- 题意:空间里有n个点P0,P1,...,Pn-1,你的任务是把它们配成n/2对(n是偶数),使得每个点恰好在一个点对中。所有点对中两点的距离之和应尽量小。
- 状态:d(i,S)表示把前i个点中,位于集合S中的元素两两配对的最小距离和
- 状态转移方程为:d(i,S)=min{|PiPj|+d(i-1,S-{i}-{j}}
- 书上的解法有些问题,正解见方法一
- 方法二:状态可以进行压缩,i的值其实隐藏在S中,S中最高位为1的即为i,所以需要一次查找,从n-1到0进行一次历编即可,整个运算下来,平均查找次数仅为2。而且方法二比方法一情况简单很多,也比较容易理解。
- 方法三:这道题用递归实现更好一些,因为只需要判断n为偶数的情况,这就是递归运算的好处,而非递归则需要全部都进行一次运算。
- 技巧:①处使用有个技巧,传递引用而不是下标,书写会方便很多。
- */
- //方法一:正解。。。
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- const int nMax=21;
- const double INF=1e10;
- int n;
- struct Node
- {
- int x,y,z;
- }node[nMax];
- double d[nMax][1<<nMax];
- void init()
- {
- scanf("%d",&n);
- for(int i=0;i<n;i++)
- scanf("%d %d %d",&node[i].x,&node[i].y,&node[i].z);
- }
- double min(double a,double b)
- {
- return a<b?a:b;
- }
- double dis(Node &a,Node &b)//①
- {
- return sqrt((double)(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()
- {
- for(int i=0;i<n;i++)
- {
- for(int s=0;s<(1<<(i+1));s++)
- {
- if(s==0) d[i][s]=0;
- else d[i][s]=INF;
- if((s & (1<<i)))
- {
- for(int j=i-1;j>=0;j--)
- if((s & (1<<j)))
- d[i][s]=min(d[i][s],dis(node[i],node[j])+d[i-1][s^(1<<i)^(1<<j)]);
- }
- else if(i!=0)
- {
- d[i][s]=d[i-1][s];
- }
- }
- }
- }
- int main()
- {
- freopen("f://data.in","r",stdin);
- init();
- solve();
- printf("%.3lf\n",d[n-1][(1<<n)-1]);
- return 0;
- }
- //方法二:推荐。。。
- //#define TEST
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- const int nMax=21;
- const double INF=1e10;
- int n,S;
- struct Node
- {
- int x,y,z;
- }node[nMax];
- double d[1<<nMax];
- void init()
- {
- scanf("%d",&n);
- for(int i=0;i<n;i++)
- scanf("%d %d %d",&node[i].x,&node[i].y,&node[i].z);
- S=1<<n;
- for(int i=1;i<S;i++)
- d[i]=-1;
- d[0]=0;
- }
- double min(double a,double b)
- {
- return a<b?a:b;
- }
- double dis(Node &a,Node &b)
- {
- return sqrt((double)(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 dp(int p)
- {
- if(d[p]!=-1) return d[p];
- d[p]=INF;
- int i,j;
- for(i=n-1;i>=0;i--)
- if(p & (1<<i))
- break;
- for(j=i-1;j>=0;j--)
- if(p & (1<<j))
- d[p]=min(d[p],dis(node[i],node[j])+dp(p^(1<<i)^(1<<j)));
- #ifdef TEST
- printf("%d %d\n",p,d[p]);
- #endif
- return d[p];
- }
- int main()
- {
- freopen("f://data.in","r",stdin);
- init();
- printf("%.3lf\n",dp(S-1));
- return 0;
- }
- //方法三:递归实现
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- const int nMax=21;
- const double INF=1e10;
- int n,S;
- struct Node
- {
- int x,y,z;
- }node[nMax];
- double d[1<<nMax];
- void init()
- {
- scanf("%d",&n);
- for(int i=0;i<n;i++)
- scanf("%d %d %d",&node[i].x,&node[i].y,&node[i].z);
- S=1<<n;
- d[0]=0;
- }
- double min(double a,double b)
- {
- return a<b?a:b;
- }
- double dis(Node &a,Node &b)
- {
- return sqrt((double)(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()
- {
- for(int s=1;s<S;s++)
- {
- int i,j;
- d[s]=INF;
- for(i=n-1;i>=0;i--)
- if(s & 1<<i)
- break;
- for(j=i-1;j>=0;j--)
- if(s & 1<<j)
- d[s]=min(d[s],dis(node[i],node[j])+d[s^(1<<i)^(1<<j)]);
- }
- }
- int main()
- {
- freopen("f://data.in","r",stdin);
- init();
- solve();
- printf("%.3lf\n",d[S-1]);
- return 0;
- }
集合上的动态规划---最优配对问题(推荐:*****) // uva 10911的更多相关文章
- 最优配对问题(集合上的动态规划) —— 状压DP
题目来源:紫书P284 题意: 给出n个点的空间坐标(n为偶数, n<=20), 把他们配成n/2对, 问:怎样配对才能使点对的距离和最小? 题解: 设dp[s]为:状态为s(s代表着某个子集) ...
- UVA 10911 Forming Quiz Teams(dp + 集合最优配对问题)
4th IIUC Inter-University Programming Contest, 2005 G Forming Quiz Teams Input: standard input Outpu ...
- DP入门(2)——DAG上的动态规划
有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.DAG模型 [嵌套矩形问题] 问题 ...
- 9.2 DAG上的动态规划
在有向无环图上的动态规划是学习动态规划的基础,很多问题都可以转化为DAG上的最长路,最短路或路径计数问题 9.2.1 DAG模型 嵌套矩形问题: 矩形之间的可嵌套关系是一种典型的二元关系,二元关系可以 ...
- 2019 年在 Raspberry Pi 「树莓派」上运行的 10 个操作系统推荐
原文:2019 年在 Raspberry Pi 「树莓派」上运行的 10 个操作系统推荐 image Raspberry Pi** 是一款基于 ARM 的单板计算机,默认运行一款称为 Raspbian ...
- UVa 103 Stacking Boxes --- DAG上的动态规划
UVa 103 题目大意:给定n个箱子,每个箱子有m个维度, 一个箱子可以嵌套在另一个箱子中当且仅当该箱子的所有的维度大小全部小于另一个箱子的相应维度, (注意箱子可以旋转,即箱子维度可以互换),求最 ...
- DAG上的动态规划之嵌套矩形
题意描述:有n个矩形,每个矩形可以用两个整数a.b描述,表示它的长和宽, 矩形(a,b)可以嵌套在矩形(c,d)当且仅当a<c且b<d, 要求选出尽量多的矩形排成一排,使得除了最后一个外, ...
- DAG 上的动态规划(训练指南—大白书)
有向无环图(DAG,Directed Acyclic Graph)上的动态规划是学习动态规划的基础.很多问题都可以转化为DAG上的最长路.最短路或路径计数问题. 一.矩形嵌套 题目描述: ...
- Oracle 12C -- 在相同的列的集合上创建多个索引
在12C中,可以在相同的列的集合上创建多个索引,但是多个索引的类型要不同.同一时刻,只有一个是可见的. SQL> create table emp_tab as select * from em ...
随机推荐
- C# WinForm动态调用远程Web服务
本文转自:http://blog.csdn.net/muyangjun/article/details/7930871 1.添加服务引用 2.在弹出的添加服务引用对话框地址栏中输入WebService ...
- C# Winform里面用Console.WriteLine输出到哪了
C# Winform里面用Console.WriteLine输出也不会报错 显示在 VS IDE 的视图→输出窗口,且只在 Debug 环境下此语句执行. 如果是 Release 环境,在 Win32 ...
- 原生js实现addClass,removeClass,hasClass方法
function hasClass(elem, cls) { cls = cls || ''; if (cls.replace(/\s/g, '').length == 0) return false ...
- 纪念一下自己的第一篇cnblog
2016-08-1016:33:22 // Netease.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iost ...
- 一个适用于层级目录结构的makefile模版
今天写了个层次化的Makefile模版,用来自动化编译项目,这个模版应当包含以下功能: 适用于层次化结构,Makefile主要内容都放在顶层目录下的Makefile.env中,子层Makefile包含 ...
- 第一章 C++简介
第一章 C++简介 1.1 C++特点 C++融合了3种不同的编程方式:C语言代表的过程性语言,C++在C语言基础上添加的类代表的面向对象语言,C++模板支持的泛型编程. 1.2 C语言及其编程 ...
- Tabbar视图切换,返回上一视图,添加item
前面有一篇博文iOS学习之Tab Bar的使用和视图切换 这是在AppDelegate里使用Tabbar,这样的程序打开就是TabbarView了,有时候我们需要给程序做一些帮助页面,或者登录页面,之 ...
- 去除wordpress由代发
在服务器上安装好wordpress后,通过程序发送邮件却显示...由<www@hostname>代发,解决办法很简单:进入程序文件夹wp-includes修改pluggable.php文件 ...
- ADO.NET笔记——使用Command执行增删改操作,通过判断ExecuteNonQuery()返回值检查是否操作成功
相关知识: ExecuteNonQuery()方法:执行CommandText属性所制定的操作,返回受影响的记录条数.该方法一般用来执行SQL中的UPDATE.INSERT和DELETE等操作 对于U ...
- 每日一“酷”之array
array--国定类型数据序列 array模块定义一个序列数据结构,看起来和list非常相似,只不过所有成员都必须是相同的基本类型. 1.初始化 array实例化时可以提高一个参数来描述允许哪个种数据 ...