zoukankan      html  css  js  c++  java
  • CH0103最短Hamilton路径 & poj2288 Islands and Brigdes【状压DP】

    虐狗宝典学习笔记:

    取出整数(n)在二进制表示下的第(k)位                                                    ((n >> k) & 1))

    取出整数(n)在二进制表示下的第(0 ~ k - 1)位(后(k)位)                    (n & ((1 << k) - 1))

    把整数(n)在二进制表示下的第(k)位取反                                                (n xor (1 << k))

    对整数(n)在二进制表示下的第(k)为赋值(1)                                          (n | (1 << k))

    对整数(n)在二进制表示下的第(k)位赋值(0)                                          (n & (~(1 << k)))

    CH0103---最短Hamilton路径

    http://contest-hunter.org:83/contest/0x00%E3%80%8C%E5%9F%BA%E6%9C%AC%E7%AE%97%E6%B3%95%E3%80%8D%E4%BE%8B%E9%A2%98/0103%20%E6%9C%80%E7%9F%ADHamilton%E8%B7%AF%E5%BE%84

    题意:

    hamilton指的是每个节点经过一次且仅经过一次的路径。现在路径上有权值,问最短的路径长度。

    思路:

    状压dp。(dp[i][j])表示在状态是(i)且最后一个经过的点时(j)时的最短路径长度。

    (dp[i][j] = min{dp[i xor (i << j)][k] + weight(k, j)})

     1 #include <bits/stdc++.h>
     2 #define inf 0x3f3f3f3f
     3 using namespace std;
     4 typedef long long LL;
     5 
     6 int n;
     7 int g[25][25];
     8 int dp[1 << 20][25];
     9 
    10 int main()
    11 {
    12     scanf("%d", &n);
    13     memset(dp, 0x3f, sizeof(dp));
    14     for(int i = 0; i < n; i++){
    15         for(int j = 0; j < n; j++){
    16             scanf("%d", &g[i][j]);
    17         }
    18     }
    19     dp[1][0] = 0;
    20     for(int i = 1; i < 1 << n; i++){
    21         for(int j = 0; j < n; j++){
    22             if(i >> j & 1){
    23                 for(int k = 0; k  < n; k++){
    24                     if((i ^ 1 << j) >> k & 1){
    25                         dp[i][j] = min(dp[i][j], dp[i ^ 1 << j][k] + g[k][j]);
    26                     }
    27                 }
    28             }
    29         }
    30     }
    31 
    32     printf("%d
    ", dp[(1 << n) - 1][n - 1]);
    33     return 0;
    34 }

    poj2288---Islands and Bridges

    http://poj.org/problem?id=2288

    题意:

    有n个岛,m座桥。每座岛有一个val,一条汉密尔顿路径的值是路径中所有点的val之和,加上所有路径上相邻的两个岛的val乘积之和,加上路径上相邻的三个岛的val乘积之和。求最大的值以及方案数。

    思路:

    和CH0103很相近,不同的是这道题要多存一个岛。(dp[stat][i][j])表示当前状态是(stat),最后一个走的岛是(j),倒数第二个走的岛是(i), (num)数组表示对应的方案数。

    当( (stat, i, j) )可达时,我们检查下一个要走的岛(k),如果此时( (stat >> k) & 1 == 0 ) 且 ( g[j][k] == 1 )说明(k)是满足条件的

    设(tmp)是下一个走(k)时的总价值。那么,(dp[stat | (1 << k)][j][k] = max(dp[stat | (1 << k)][j][k], tmp))

    如果(tmp == dp[stat | (1 << k)][j][k]),那么,(num[stat | (1 << k)][j][k] += num[stat][i][j])。否则(num[stat | (1 << k)][j][k] = num[stat][i][j] )

    那么要如何求(tmp) 呢。

    首先当(j)可以走到(k)时,肯定有 (tmp = dp[stat][i][j] + val[k] + val[j] * val[k] )

    如果此时还有(g[i][k] == 1) 那么(tmp += val[i] * val[j] * val[k])

    最后我们对于(stat = (1 << n) - 1)枚举(i)和(j),找到最大的结果。

    注意方案数会超出int。还需要注意(n = 1)时的特殊情况。

    注意内存省着点,会MLE

      1 //#include <bits/stdc++.h>
      2 #include <iostream>
      3 #include <algorithm>
      4 #include <cmath>
      5 #include <cstring>
      6 #include <stdio.h>
      7 #include <vector>
      8 #include <map>
      9 #include <set>
     10 #define inf 0x3f3f3f3f
     11 using namespace std;
     12 typedef long long LL;
     13 
     14 int n, m, q;
     15 bool g[13][13];
     16 int dp[1 << 13][13][13];
     17 LL num[1 << 13][13][13];
     18 int val[13];
     19 int cnt;
     20 
     21 void hamilton()
     22 {
     23     memset(dp, -1, sizeof(dp));
     24     memset(num, 0, sizeof(num));
     25     for(int i = 0; i < n; i++){
     26         for(int j = 0; j < n; j++){
     27             if(g[i][j]){
     28                 dp[1 << i | 1 << j][i][j] = val[i] + val[j] + val[i] * val[j];
     29                 num[1 << i | 1 << j][i][j] = 1;
     30             }
     31         }
     32     }
     33 
     34     for(int stat = 1; stat < 1 << n; stat++){
     35         for(int i = 0; i < n; i++){
     36             if((stat >> i) & 1){
     37                 for(int j = 0; j < n; j++){
     38                     if((stat >> j) & 1){
     39                         if(g[i][j] && dp[stat][i][j] != -1){
     40                             for(int k = 0; k < n; k++){
     41                                 if(g[j][k] && k != i && ((stat >> k) & 1) == 0){
     42                                     int tmp = dp[stat][i][j] + val[k] + val[k] * val[j];
     43                                     if(g[i][k]){
     44                                         tmp += val[i] * val[j] * val[k];
     45                                     }
     46                                     if(tmp > dp[stat | (1 << k)][j][k]){
     47                                         dp[stat | (1 << k)][j][k] = tmp;
     48                                         num[stat | (1 << k)][j][k] = num[stat][i][j];
     49                                     }
     50                                     else if(tmp == dp[stat | (1 << k)][j][k]){
     51                                         num[stat | (1 << k)][j][k] += num[stat][i][j];
     52                                     }
     53                                 }
     54                             }
     55                         }
     56                     }
     57                 }
     58             }
     59         }
     60     }
     61     //return dp[(1 << n) - 1][n - 1];
     62 }
     63 
     64 int main()
     65 {
     66     scanf("%d", &q);
     67     while(q--){
     68         memset(g, 0, sizeof(g));
     69         scanf("%d%d", &n, &m);
     70         for(int i = 0; i < n; i++){
     71             scanf("%d", &val[i]);
     72         }
     73         for(int i = 0; i < m; i++){
     74             int u, v;
     75             scanf("%d%d", &u, &v);
     76             g[u - 1][v - 1] = 1;
     77             g[v - 1][u - 1] = 1;
     78         }
     79         if(n == 1){
     80             printf("%d 1
    ", val[0]);
     81             continue;
     82         }
     83 
     84         hamilton();
     85         int maxi = 0;
     86         LL ans = 0;
     87         for(int i = 0; i < n; i++){
     88             for(int j = 0; j < n; j++){
     89                 if(g[i][j]){
     90                     if(maxi < dp[(1 << n) - 1][i][j]){
     91                         maxi = dp[(1 << n) - 1][i][j];
     92                         ans = num[(1 << n) - 1][i][j];
     93                     }
     94                     else if(maxi == dp[(1 << n) - 1][i][j]){
     95                         ans += num[(1 << n) - 1][i][j];
     96                     }
     97                 }
     98             }
     99         }
    100 
    101         printf("%d %lld
    ", maxi, ans / 2);
    102     }
    103     return 0;
    104 }
  • 相关阅读:
    20145230《java学习笔记》第十周学习总结
    20145230《java学习笔记》第九周学习总结
    20145230《java程序设计》 第四次实验报告
    20145230《java程序设计》第三次试验报告
    20145230 《Java程序设计》第8周学习总结
    20145230java实验报告二
    20145230《java学习笔记》第七周学习总结
    20145230java实验报告1
    20145230《java程序设计》第6周学习总结
    20145228 《信息安全系统设计基础》第五周学习总结 (2)
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9932142.html
Copyright © 2011-2022 走看看