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\n", 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\n");
118     else
119         printf("%lld %lld\n", ans1, ans2 / 2);
120 }
时间: 2024-10-06 02:38:06

DP:Islands and Bridges(POJ 2288)的相关文章

POJ 2288 Islands and Bridges(状压dp)

Language: Default Islands and Bridges Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 9312   Accepted: 2424 Description Given a map of islands and bridges that connect these islands, a Hamilton path, as we all know, is a path along the b

POJ 2288 Islands and Bridges 哈密尔顿路 状态压缩DP

找最长的其实是很裸的状态压缩DP,棘手的地方是要统计数量,其实只要再来一个数组存就好. 不过代码比较长,细节要注意的地方毕较多,wa了很多发,还是要仔细啊 用递推和记忆化搜索分别写了一遍 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <

poj 2288 Islands and Bridges

题意: 给你一个双向连通图,求 获得权值最大 的 哈密顿通路的 权值 和 这个权值对应的数目: 其中权值计算方法是  列如 ABCD  权值是a+b+c+d+ab+bc+cd 如果 A,B,C  和B,C,D 可构成三角形分别加上abc,bcd: 这个题 和poj 3311  很相像: 那个需要记录一个最后到达的地方   这个需要记录俩个罢了 DP[i][a][b]其中 i  二进制 中1表示这个点走过了   最后走的的 的是b>>a 因为对于已经走过了{1,2,3,4,,5,6,..,N}

poj2288(Islands and Bridges) 状压DP

题目链接:http://poj.org/problem?id=2288 题意:每个点有一个权值Vi,找一条哈密顿路径,路径的权值来自三条:1 路径上的Vi之和 2 所有相邻点对ij的Vi*Vj之和 3 相邻连续三点i,j,k(并且三点要构成三角形)Vi*Vj*Vk之和. 解法:dp[st][i][j]表示从j走到i并且剩下集合st没有走的最大权值.关于路径书,在转移的时候顺便计算即可:这道题令自己恶心了好久,最后原因是自己犯了一个严重错误,题目读错了,没有读到Vi*Vj*Vk要保证ijk能够构成

poj 2288 Islands and Bridges_状态压缩dp_哈密尔顿回路问题

题目链接 题目描写叙述:哈密尔顿路问题.n个点,每个点有权值,设哈密尔顿路为 C1C2...Cn,Ci的权值为Vi,一条哈密尔顿路的值分为三部分计算: 1.每个点的权值之和2.对于图中的每一条CiCi+1,加上Vi*Vi+1 3.对于路径中的连续三个点:CiCi+1Ci+2,若在图中,三点构成三角形,则要加上Vi*Vi+1*Vi+2 求一条汉密尔顿路能够获得的最大值,而且还要输出有多少条这种哈密尔顿路. 这道题的状态感觉不是非常难想,由于依据一般的哈密尔顿路问题,首先想到的是设计二维状态,dp[

【汉密尔顿、DP|状态压缩】POJ-2288 Islands and Bridges

Islands and Bridges Time Limit: 4000MS   Memory Limit: 65536K       Description Given a map of islands and bridges that connect these islands, a Hamilton path, as we all know, is a path along the bridges such that it visits each island exactly once.

HDU 1668 Islands and Bridges

Islands and Bridges Time Limit: 4000ms Memory Limit: 65536KB This problem will be judged on HDU. Original ID: 166864-bit integer IO format: %I64d      Java class name: Main Given a map of islands and bridges that connect these islands, a Hamilton pat

POJ2288:Islands and Bridges(状态压缩)

Description Given a map of islands and bridges that connect these islands, a Hamilton path, as we all know, is a path along the bridges such that it visits each island exactly once. On our map, there is also a positive integer value associated with e

POJ2288 Islands and Bridges

Description Given a map of islands and bridges that connect these islands, a Hamilton path, as we all know, is a path along the bridges such that it visits each island exactly once. On our map, there is also a positive integer value associated with e