zoukankan      html  css  js  c++  java
  • hlg2130一笔画【状压dp】

    一笔画
    Time Limit: 3000 MS Memory Limit: 32768 K
    Total Submit: 6(2 users) Total Accepted: 1(1 users) Rating:  Special Judge: No
    Description

    小明喜欢画画,今天他在地上捡起了一张纸,这张纸上有好多个点。小明就想,如果我用铅笔一次性(中间不抬笔)把这些点连起来,那么我的铅笔需要在纸上走多长的路呢?

    Input

    第一行,测试组数t。

    每组第一行一个正整数N(1<=N<=15),表示点的个数。

    接下来n行,每行两个整数xi,yi(0<=xi,yi<=100),表示点的坐标。

    Output

    求出连接n个点的最短路径长度。保留两位小数。

    Sample Input

    2

    3

    0 0

    0 1

    0 2

    3

    0 0

    0 1

    1 0

    Sample Output

    2.00

    2.00

    题目描述很简单

    我刚开始做这场练习赛的时候没有做出来

    后来作者说是状压dp的时候就开始有点思路

    现在终于坐上来了

    dp[i][j]表示状态为i, j为笔画的最后一个点的最小路径

    那么对于一个未加入集合中的点 k

    dp[i | ( 1 << ( k - 1) )][k] = min(dp[i | ( 1 << ( k - 1) )][k], dp[i][j] + dist[j][k]);

    于是我就想到了一个10^8的算法

    每次都枚举一次插入的点

    然后TLE了

    我们可以想一下‘|’的性质   每一次的‘|’都会是原来的数增大或不变

    那么只要依次向后枚举每种状态  那么新状态一定在这个之后  

    并且该状态一定为最优解

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 using namespace std;
     6 
     7 const int maxn = 20;
     8 
     9 struct Node {
    10     double x, y;
    11 }node[maxn];
    12 
    13 double dp[1 << 16][maxn];
    14 
    15 double dis[maxn][maxn];
    16 bool is[1 << 16][maxn];
    17 
    18 int xx[1 << 16][maxn];
    19 
    20 int main() {
    21     int M = 1 << 15;
    22     memset(is, 0, sizeof(is));
    23     for(int i = 0; i < M; i++) {
    24         for(int j = 1; j <= 15; j++) {
    25             if(( i & ( 1 << ( j - 1) ) ) != 0) {
    26                 is[i][j] = true;
    27             }
    28         }
    29     }
    30     for(int i = 0; i < M; i++) {
    31         for(int j = 1; j <= 15; j++) {
    32             xx[i][j] = ( i | ( 1 << ( j - 1) ) );
    33         }
    34     }
    35     int t, n;
    36     scanf("%d",&t);
    37     while(t--) {
    38         scanf("%d",&n);
    39         for(int i = 1; i <= n; i++) {
    40             scanf("%lf %lf",&node[i].x, &node[i].y);
    41         }
    42         for(int i = 1; i <= n; i++) {
    43             dis[i][i] = 0;
    44             for(int j = i + 1; j <= n; j++) {
    45                 dis[i][j] = dis[j][i] = sqrt( (node[i].x - node[j].x) * (node[i].x - node[j].x) + (node[i].y - node[j].y) * (node[i].y - node[j].y) );
    46             }
    47         }
    48         int N = 1 << n;
    49         for(int i = 0; i < N; i++) {
    50             for(int j = 1; j <= n; j++) {
    51                 dp[i][j] = 10000.0;
    52             }
    53         }
    54         dp[1][1] = 0;
    55         for(int i = 1, j = 1; i < N; i <<= 1, j++) {
    56             dp[i][j] = 0;
    57         }
    58         for(int i = 0; i < N; i++) {
    59             for(int j = 1; j <= n; j++) {
    60                 if(is[i][j]) {
    61                     for(int k = 1; k <= n; k++) {
    62                         if(!is[i][k]) {
    63                             dp[xx[i][k]][k] = min(dp[xx[i][k]][k], dp[i][j] + dis[j][k]);
    64                         }
    65                     }
    66                 }
    67             }
    68         }
    69         double ans = 10000.0;
    70         for(int i = 1; i <= n; i++) {
    71             ans = min(ans, dp[N - 1][i]);
    72         }
    73         printf("%.2lf
    ", ans);
    74     }
    75     return 0;
    76 }
    View Code
  • 相关阅读:
    Openjudge-2694-逆波兰表达式
    POJ-3984-迷宫问题
    HUST软件与微电子学院第八届程序设计竞赛-小乐乐下象棋
    LiberOJ-#6000. 「网络流 24 题」搭配飞行员 (二分图匹配)
    BZOJ-3172: [Tjoi2013]单词 (AC自动姬 fail树)
    BZOJ-1036: [ZJOI2008]树的统计Count(树链剖分+线段树)
    HDU-3966 Aragorn's Story(树链剖分+线段树)
    hihoCoder-1036 Trie图(AC自动姬)
    WHYZOJ-#14 数列(矩阵快速幂)
    WHYZOJ-#66 穿越七色虹(二分)
  • 原文地址:https://www.cnblogs.com/zhanzhao/p/4079679.html
Copyright © 2011-2022 走看看