• DP:Islands and Bridges(POJ 2288)


                    2015-09-21

                    

                    造桥基建工程

      题目大意,就是有n座岛和k座桥,要你找一条哈密顿圈(找完所有的岛,并且每个岛只经过一次),当经过一座岛就加上岛的价值,如果两岛联通,则加上两座岛的价值之积,如果三座岛之间构成三角联通,则再加上三岛之积,问最大价值的哈密顿圈和最大价值和哈密顿圈的个数

      哈密顿圈是是一个NP完全的问题,用DP就可以解决这个问题,现在的问题就是,怎么解决呢?

      首先我们要明确,这一题要用DP做什么,首先这一题的最后肯定要求到最后岛全部都通过的情况,然后还需要保留前两个岛的信息

      那么这个时候我们可以想到用状态压缩去做(因为这里岛只能经过一次,而且经过以后状态都是等效的)101111,就表示第五个岛还没被经过,本来呢这个状态压缩应该是保留状态的,但是这样一来我们就需要保留1<<n个*3个维度,那么这一题我们可以放弃了,因为内存肯定不够,所以我们要想着优化储存空间,由于我们只用担心前两个岛是什么,而不是岛的所在状态(反正表示也是1001111)这样的,所以我们可以把两个岛的维度改为n*n,那么最后dp就是一个[1<<n][n][n]的三维数组

      具体而言,对于不合法的位置,我们老方法,要定义其为-1,同时还要判断图是否联通

      我们先从i=1(0000....0001)开始枚举,表示岛已经经过的位置,如果我们需要上一次还没来到这个岛的位置的状态,我们使用i^(1<<(j-1))这个方法,并且判断第j个岛的前两座岛是否有冲突。

      如果算出来的dp值比dp[i][j][k]要大,则更新,并且num是继承dp[state_old][k][q]的状态,如果想等,则使num[i][j][k]+=num[state_old][k][q](表示还有更多的路与此状态相关)。

      最后基准状态,q=0的时候可以放入岛的价值,那么最后就可以一起处理了,并且只有一个岛的时候,要单独处理,并且数据类型要是long long

      参考:http://blog.csdn.net/lenleaves/article/details/7981788

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 static int islands_value[14];
      6 int map[14][14];
      7 long long dp[1 << 13][14][14];//因为要保存两个以上状态,所以必须是三维数组,前面一位是状态数
      8 long long num[1 << 13][14][14];
      9 
     10 void Search(const int);
     11 static int If_Valid(const int, const int);
     12 
     13 int main(void)
     14 {
     15     int sum_islands, sum_paths, sum_obj, i, j, k, x, y;
     16     
     17     scanf("%d", &sum_obj);
     18     for (i = 0; i < sum_obj; i++)//输入
     19     {
     20         scanf("%d%d", &sum_islands, &sum_paths);
     21         for (j = 1; j <= sum_islands; j++)
     22             scanf("%d", &islands_value[j]);
     23         memset(map, 0, sizeof(map));
     24         memset(dp, -1, sizeof(dp));
     25         memset(num, 0, sizeof(num));
     26         for (k = 0; k < sum_paths; k++)
     27         {
     28             scanf("%d%d", &x, &y);
     29             map[x][y] = map[y][x] = 1;//读图1
     30         }
     31         Search(sum_islands);
     32     }
     33     return 0;
     34 }
     35 
     36 static int If_Valid(const int x, const int y)
     37 {
     38     /*If_Value函数:
     39      功能:判断y位置是否被访问过
     40      返回值:被访问过返回1,未被访问放回0,如果y是0,则就是基准情况,一定要给通过
     41     */
     42     if (y == 0) return 1;
     43     if (x&(1 << (y - 1))) return 1;
     44     else return 0;
     45 }
     46 
     47 void Search(const int sum_islands)
     48 {
     49     int i, j, k, q, state_old;
     50     long long tmp, ans1, ans2;
     51 
     52     if (sum_islands == 1)
     53     {
     54         printf("%d 1
    ", islands_value[1]);
     55         return;
     56     }
     57     for (j = 1; j <= sum_islands; j++)
     58     {
     59         dp[1 << (j - 1)][j][0] = islands_value[j];
     60         num[1 << (j - 1)][j][0] = 1;//初始化的时候价值为1
     61     }
     62     for (i = 1; i < (1 << sum_islands);i++)
     63     {
     64         for (j = 1; j <= sum_islands; j++)
     65         {
     66             state_old = i ^ (1 << (j - 1));//得到当j还没有出现时候的位置
     67             if (If_Valid(i, j))//这个位置就是要考虑的位置
     68             {
     69                 for (k = 1; k <= sum_islands; k++)
     70                 {
     71                     if (k != j && map[j][k] && If_Valid(i, k))
     72                     {
     73                         for (q = 0; q <= sum_islands; q++)
     74                         {
     75                             if (!map[k][q] && q) continue;//q = 0的时候是没有意义的
     76                             if (q != j&&q != k
     77                                 && If_Valid(state_old, q)//是否是需要的q
     78                                 && dp[state_old][k][q] != -1)//这个位置一定要有意义
     79                             {
     80                                 tmp = islands_value[j] + islands_value[j] * islands_value[k] + dp[state_old][k][q];
     81                                 if (map[j][q])
     82                                     //假设j和q是联通的
     83                                     tmp += islands_value[j] * islands_value[k] * islands_value[q];
     84                                 if (tmp == dp[i][j][k])
     85                                     //如果得到的结果是和ijk这个位置已经重复了,则自增(中间状态)
     86                                     num[i][j][k] += num[state_old][k][q];
     87                                 if (tmp > dp[i][j][k])
     88                                     //如果比ijk这个状态还要大,则更新dp,继承num
     89                                 {
     90                                     dp[i][j][k] = tmp;
     91                                     num[i][j][k] = num[state_old][k][q];
     92                                 }
     93                             }
     94                         }
     95                     }
     96                 }
     97             }
     98         }
     99     }
    100     for (ans1 = -1, ans2 = 0, j = 1; j <= sum_islands; j++)
    101     {
    102         for (k = 1; k <= sum_islands; k++)
    103         {
    104             if (k != j)
    105             {
    106                 if (ans1 == dp[(1 << sum_islands) - 1][j][k])
    107                     ans2 += num[(1 << sum_islands) - 1][j][k];
    108                 if (ans1 < dp[(1 << sum_islands) - 1][j][k])
    109                 {
    110                     ans1 = dp[(1 << sum_islands) - 1][j][k];
    111                     ans2 = num[(1 << sum_islands) - 1][j][k];
    112                 }
    113             }
    114         }
    115     }
    116     if (ans1 == -1)
    117         printf("0 0
    ");
    118     else
    119         printf("%lld %lld
    ", ans1, ans2 / 2);
    120 }
  • 相关阅读:
    svn cleanup failed–previous operation has not finished 解决方法
    开源SNS社区系统推荐
    从网络获取图片本地保存
    MS SQL Server 数据库连接字符串
    KeepAlive
    Configure Git in debian
    sqlserver query time
    RPi Text to Speech (Speech Synthesis)
    SQL Joins with C# LINQ
    search or reseed identity columns in sqlserver 2008
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/4824920.html
Copyright © 2020-2023  润新知