集合上的动态规划—最优配对问题

举报
Linux猿 发表于 2021/08/05 22:47:23 2021/08/05
【摘要】   /*提醒推荐:五星刘汝佳《算法竞赛入门经典》,集合上的动态规划---最优配对问题题意:空间里有n个点P0,P1,...,Pn-1,你的任务是把它们配成n/2对(n是偶数),使得每个点恰好在一个点对中。所有点对中两点的距离之和应尽量小。状态:d(i,S)表示把前i个点中,位于集合S中的元素两两配对的最小距离和状态转移方程为:d(i,S)=min{|PiPj|+d...

 


  
  1. /*
  2. 提醒推荐:五星
  3. 刘汝佳《算法竞赛入门经典》,集合上的动态规划---最优配对问题
  4. 题意:空间里有n个点P0,P1,...,Pn-1,你的任务是把它们配成n/2对(n是偶数),使得每个点恰好在一个点对中。所有点对中两点的距离之和应尽量小。
  5. 状态:d(i,S)表示把前i个点中,位于集合S中的元素两两配对的最小距离和
  6. 状态转移方程为:d(i,S)=min{|PiPj|+d(i-1,S-{i}-{j}}
  7. 书上的解法有些问题,正解见方法一
  8. 方法二:状态可以进行压缩,i的值其实隐藏在S中,S中最高位为1的即为i,所以需要一次查找,从n-1到0进行一次历编即可,整个运算下来,平均查找次数仅为2。而且方法二比方法一情况简单很多,也比较容易理解。
  9. 方法三:这道题用递归实现更好一些,因为只需要判断n为偶数的情况,这就是递归运算的好处,而非递归则需要全部都进行一次运算。
  10. 技巧:①处使用有个技巧,传递引用而不是下标,书写会方便很多。
  11. */
  12. //方法一:正解。。。
  13. #include <cstdio>
  14. #include <cstring>
  15. #include <cmath>
  16. const int nMax=21;
  17. const double INF=1e10;
  18. int n;
  19. struct Node
  20. {
  21. int x,y,z;
  22. }node[nMax];
  23. double d[nMax][1<<nMax];
  24. void init()
  25. {
  26. scanf("%d",&n);
  27. for(int i=0;i<n;i++)
  28. scanf("%d %d %d",&node[i].x,&node[i].y,&node[i].z);
  29. }
  30. double min(double a,double b)
  31. {
  32. return a<b?a:b;
  33. }
  34. double dis(Node &a,Node &b)//①
  35. {
  36. 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));
  37. }
  38. void solve()
  39. {
  40. for(int i=0;i<n;i++)
  41. {
  42. for(int s=0;s<(1<<(i+1));s++)
  43. {
  44. if(s==0) d[i][s]=0;
  45. else d[i][s]=INF;
  46. if((s & (1<<i)))
  47. {
  48. for(int j=i-1;j>=0;j--)
  49. if((s & (1<<j)))
  50. d[i][s]=min(d[i][s],dis(node[i],node[j])+d[i-1][s^(1<<i)^(1<<j)]);
  51. }
  52. else if(i!=0)
  53. {
  54. d[i][s]=d[i-1][s];
  55. }
  56. }
  57. }
  58. }
  59. int main()
  60. {
  61. freopen("f://data.in","r",stdin);
  62. init();
  63. solve();
  64. printf("%.3lf\n",d[n-1][(1<<n)-1]);
  65. return 0;
  66. }
  67. //方法二:推荐。。。
  68. //#define TEST
  69. #include <cstdio>
  70. #include <cstring>
  71. #include <cmath>
  72. const int nMax=21;
  73. const double INF=1e10;
  74. int n,S;
  75. struct Node
  76. {
  77. int x,y,z;
  78. }node[nMax];
  79. double d[1<<nMax];
  80. void init()
  81. {
  82. scanf("%d",&n);
  83. for(int i=0;i<n;i++)
  84. scanf("%d %d %d",&node[i].x,&node[i].y,&node[i].z);
  85. S=1<<n;
  86. for(int i=1;i<S;i++)
  87. d[i]=-1;
  88. d[0]=0;
  89. }
  90. double min(double a,double b)
  91. {
  92. return a<b?a:b;
  93. }
  94. double dis(Node &a,Node &b)
  95. {
  96. 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));
  97. }
  98. double dp(int p)
  99. {
  100. if(d[p]!=-1) return d[p];
  101. d[p]=INF;
  102. int i,j;
  103. for(i=n-1;i>=0;i--)
  104. if(p & (1<<i))
  105. break;
  106. for(j=i-1;j>=0;j--)
  107. if(p & (1<<j))
  108. d[p]=min(d[p],dis(node[i],node[j])+dp(p^(1<<i)^(1<<j)));
  109. #ifdef TEST
  110. printf("%d %d\n",p,d[p]);
  111. #endif
  112. return d[p];
  113. }
  114. int main()
  115. {
  116. freopen("f://data.in","r",stdin);
  117. init();
  118. printf("%.3lf\n",dp(S-1));
  119. return 0;
  120. }
  121. //方法三:递归实现
  122. #include <cstdio>
  123. #include <cstring>
  124. #include <cmath>
  125. const int nMax=21;
  126. const double INF=1e10;
  127. int n,S;
  128. struct Node
  129. {
  130. int x,y,z;
  131. }node[nMax];
  132. double d[1<<nMax];
  133. void init()
  134. {
  135. scanf("%d",&n);
  136. for(int i=0;i<n;i++)
  137. scanf("%d %d %d",&node[i].x,&node[i].y,&node[i].z);
  138. S=1<<n;
  139. d[0]=0;
  140. }
  141. double min(double a,double b)
  142. {
  143. return a<b?a:b;
  144. }
  145. double dis(Node &a,Node &b)
  146. {
  147. 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));
  148. }
  149. void solve()
  150. {
  151. for(int s=1;s<S;s++)
  152. {
  153. int i,j;
  154. d[s]=INF;
  155. for(i=n-1;i>=0;i--)
  156. if(s & 1<<i)
  157. break;
  158. for(j=i-1;j>=0;j--)
  159. if(s & 1<<j)
  160. d[s]=min(d[s],dis(node[i],node[j])+d[s^(1<<i)^(1<<j)]);
  161. }
  162. }
  163. int main()
  164. {
  165. freopen("f://data.in","r",stdin);
  166. init();
  167. solve();
  168. printf("%.3lf\n",d[S-1]);
  169. return 0;
  170. }

转自~>

文章来源: blog.csdn.net,作者:Linux猿,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nyist_zxp/article/details/21557389

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。