zoukankan      html  css  js  c++  java
  • 集合上的动态规划--最优配对问题

     转自此博客

    题目:刘汝佳《算法竞赛入门经典》,集合上的动态规划---最优配对问题 题意:空间里有n个点P0,P1,...,Pn-1,你的任务是把它们配成n/2对(n是偶数),使得每个点恰好在一个点对中。所有点对中两点的距离之和应尽量小。状态:d(i,S)表示把前i个点中,位于集合S中的元素两两配对的最小距离和 状态转移方程为:d(i,S)=min{|PiPj|+d(i-1,S-{i}-{j}} 

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <math.h>
     5 #include <algorithm>
     6 using namespace std;
     7 const int N = 20;
     8 const int INF = 0x3f3f3f3f;
     9 double d[N + 5][(1 << N) + 10];
    10 struct Node
    11 {
    12     int x, y, z;
    13 }node[N + 10];
    14 double dist(int n1, int n2)
    15 {
    16     return sqrt( double( (node[n1].x - node[n2].x) * (node[n1].x - node[n2].x) + (node[n1].y - node[n2].y) * (node[n1].y - node[n2].y) + (node[n1].z - node[n2].z) * (node[n1].z - node[n2].z)));
    17 }
    18 int main()
    19 {
    20     int n;
    21     scanf("%d", &n);
    22     for(int i = 1; i <= n; i++)
    23     {
    24         scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].z);
    25     }
    26     for(int i = 0; i < n; i++)
    27     {
    28         for(int S = 0; S < (1 << (i + 1) ); S++)
    29         {
    30             if(S == 0)
    31                 d[i][S] = 0;
    32             else
    33                 d[i][S] = INF;
    34             if(S & (1 << i))
    35             {
    36                 for(int j = 0; j < i; j++)
    37                 {
    38                     if(S & (1 << j) )
    39                         d[i][S] = min(d[i][S], dist(i, j) + d[i - 1][S ^ (1 << i) ^ (1 << j)]);
    40                 }
    41             }
    42             else if(i != 0)
    43             {
    44                 d[i][S] = d[i - 1][S];
    45             }
    46         }
    47     }
    48     printf("%.3lf
    ", d[n - 1][(1 << n) - 1]);
    49     return 0;
    50 }
    View Code

    状态可以进行压缩,i的值其实隐藏在S中,S中最高位为1的即为i,所以需要一次查找,从n-1到0进行一次历编即可,整个运算下来,平均查找次数仅为2。而且方法二比方法一情况简单很多,也比较容易理解。 

     1 #include <cstring>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cmath>
     5 #include <iostream>
     6 using namespace std;
     7 const int N = 20;
     8 const int INF = 0x3f3f3f3f;
     9 double d[(1 << N) + 10];
    10 struct Node
    11 {
    12     int x, y, z;
    13 }node[N + 10];
    14 int n, S;
    15 double dist(int n1, int n2)
    16 {
    17     return sqrt( double( (node[n1].x - node[n2].x) * (node[n1].x - node[n2].x) + (node[n1].y - node[n2].y) * (node[n1].y - node[n2].y) + (node[n1].z - node[n2].z) * (node[n1].z - node[n2].z)));
    18 }
    19 void input()
    20 {
    21     for(int i = 0; i < n; i++)
    22     {
    23         scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].z);
    24     }
    25     S = 1 << n;
    26     d[0] = 0;
    27 }
    28 void solve()  
    29 {
    30     for(int s = 1; s < S; s++)
    31     {
    32         int i, j;
    33         d[s] = INF;
    34         for(i = n - 1; i >= 0; i--)  //d[s]就是前i个位于集合s中距离最小,只要找到i,再从i往前找j不就行了。
    35             if(s & (1 << i))
    36                 break;
    37         for(j = i - 1; j >= 0; j--)
    38             if(s & (1 << j))
    39                 d[s] = min(d[s], dist(i, j) + d[s ^ (1 << i) ^ (1 << j)]);
    40     }
    41 }
    42 int main()
    43 {
    44     scanf("%d", &n);
    45     input();
    46     solve();
    47     printf("%0.3lf
    ", d[S - 1]);
    48     return 0;
    49 }
    View Code

    这道题用递归实现更好一些,因为只需要判断n为偶数的情况,这就是递归运算的好处,而非递归则需要全部都进行一次运算。 

     1 #include <cstring>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cmath>
     5 #include <iostream>
     6 using namespace std;
     7 const int N = 20;
     8 const int INF = 0x3f3f3f3f;
     9 double d[(1 << N) + 10];
    10 struct Node
    11 {
    12     int x, y, z;
    13 }node[N + 10];
    14 int n, S;
    15 double dist(int n1, int n2)
    16 {
    17     return sqrt( double( (node[n1].x - node[n2].x) * (node[n1].x - node[n2].x) + (node[n1].y - node[n2].y) * (node[n1].y - node[n2].y) + (node[n1].z - node[n2].z) * (node[n1].z - node[n2].z)));
    18 }
    19 void input()
    20 {
    21     scanf("%d", &n);
    22     for(int i = 0; i < n; i++)
    23     {
    24         scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].z);
    25     }
    26     S = 1 << n;
    27     //memset(d, INF, sizeof(d)); 慎用emset()
    28     for(int i = 0; i < S; i++)
    29         d[i] = INF;
    30     d[0] = 0;
    31 
    32 }
    33 double dp(int s)
    34 {
    35     if(d[s] != INF)
    36         return d[s];
    37     int i, j;
    38     for(i = n - 1; i >= 0; i--)
    39         if(s & (1 << i))
    40             break;
    41     for(j = i - 1; j >= 0; j--)
    42         if(s & (1 << j))
    43             d[s] = min(d[s], dp(s ^ (1 << i) ^ (1 << j)) + dist(i, j));
    44     return d[s];
    45 }
    46 int main()
    47 {
    48     input();
    49     printf("%0.3lf
    ", dp(S - 1));
    50     return 0;
    51 }
    View Code
  • 相关阅读:
    C 语言编程经典 100 例
    visual studio.net已检测到指定的web服务器运行的不是asp.net1.1版。无法运行asp.net web应用程序
    如何编译及运行java
    VBScript 函数集
    SQL SERVER定时作业的设置方法
    显示桌面按钮不小心被删,有什么办法找回?
    随机抽取n个记录的SQL
    打开项目时提示如下错误:Visual Studio .NET 无法创建应用程序 。问题很可能是因为本地 Web 服务器上没有安装所需的组件
    简单的数据库连接
    ASP中各种数据库连接代码
  • 原文地址:https://www.cnblogs.com/zhaopAC/p/5282748.html
Copyright © 2011-2022 走看看