题目链接

题目描述:哈密尔顿路问题。n个点,每一个点有权值,设哈密尔顿路为 C1C2...Cn,Ci的权值为Vi,一条哈密尔顿路的值分为三部分计算:

1.每一个点的权值之和

2.对于图中的每一条CiCi+1,加上Vi*Vi+1

3.对于路径中的连续三个点:CiCi+1Ci+2,若在图中,三点构成三角形,则要加上Vi*Vi+1*Vi+2

求一条汉密尔顿路可以获得的最大值,并且还要输出有多少条这样的哈密尔顿路。



这道题的状态感觉不是很难想,因为根据一般的哈密尔顿路问题,首先想到的是设计二维状态,dp[i , s]表示当前在i点,走过的点形成状态集合s。但是这道题在求解值的时候有一个不一样的地方,就是第三部分,如果还是设计成二维的状态,就会很麻烦,因为每加入一个新点,要判断新点、当前点、倒数第二个点是否构成三角形,所以要记录倒数第二个点。很自然地想到扩展状态的维数,增加一维,记录倒数第二个点。



1>  设计状态:

dp[i , j , s]表示当前站在j点,前一个点是i点,形成的状态集合是s,此时的最大值,way[i , j , s]记录当前状态下达到最大值的路径数;

2>  状态转移:

设k点不在集合s中,且存在边<j , k>

设q为下步到达k点获得的最大值

令r = s + (1<<k),为当前站在点k,前一个点为j,形成状态集合r

若i,j,k形成三角形,则q = dp[i][j][s] + v[k] + v[j]*v[k] + v[i]*v[j]*v[k]

否则,q = dp[i][j][s] + v[k] + v[j]*v[k];

若q大于dp[j][k][r];则:

dp[j][k][r] = q

way[j][k][r] = way[i][j][s];

若q等于dp[j][k][r],则:

way[j][k][r] += way[i][j][s];

3>  初始化:

显然,若i点到j点有边,则: 

dp[i][j][(1<<i)+(1<<j)] = v[i] + v[j] + v[i]*v[j];

way[i][j][(1<<i)+(1<<j)] = 1;

4>  结果的产生:

最后的结果我们要枚举点i和j,找到最大的dp[i][j][(1<<n)-1],并且更新记录路径数ansp,最后ansp要除2才是结果,因为题目最后一句话,正向反向是一样的路。

此外,需要注意的是discuss提到的特殊情况,要用__int64,并且注意n等于1时,最大值就是第一个点的权值,路径数为1。

#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN =13;
const int MAXS =1<<MAXN|1;
#define ll __int64
ll dp[MAXN][MAXN][MAXS],way[MAXN][MAXN][MAXS];
int map[MAXN][MAXN],v[MAXN];
int n,m,s;
void stateDp(){
int i,j,p,k;
memset(dp,-1,sizeof(dp));
memset(way,0,sizeof(way));
for(i=0;i<n;i++)
for(j=0;j<n;j++){
if(map[i][j]){
dp[i][j][(1<<i)+(1<<j)]=v[i]+v[j]+v[i]*v[j];
way[i][j][(1<<i)+(1<<j)]=1;
}
}
for(p=3;p<s;p++){
for(i=0;i<n;i++){
if(!(p&1<<i))//如果该状态第i城市没有路过就跳过
continue;
for(j=0;j<n;j++){
if(i==j||!(p&1<<j)||dp[i][j][p]==-1)
continue;
for(k=0;k<n;k++){
if(p&1<<k||!map[j][k])//如果k存在该状态则跳过
continue;
int r=p+(1<<k);//状态加入k城市
ll q=dp[i][j][p]+v[k]+v[j]*v[k];//更新价值
if(map[i][k]){//当构成环时更新价值
q+=v[i]*v[j]*v[k];
}
if(q>dp[j][k][r]){
dp[j][k][r]=q;
way[j][k][r]=way[i][j][p];
}else if(q==dp[j][k][r]){//相等时,有多个相等价值路径
way[j][k][r]+=way[i][j][p];
}
}
}
}
}
}
int main(int argc, char** argv) { int t,x,y,i,j;
scanf("%d",&t);
while(t--){
memset(map,0,sizeof(map));
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
scanf("%d",&v[i]);
for(i=0;i<m;i++){
scanf("%d%d",&x,&y);
map[x-1][y-1]=map[y-1][x-1]=1;
}
s=1<<n;
if(n==1){
printf("%d %d\n",v[0],1);
continue;
}
stateDp();
ll ansv=-1,ansp=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++){
if(i==j)continue;
if(dp[i][j][s-1]>ansv){//s-1为经过所有岛
ansv=dp[i][j][s-1];
ansp=way[i][j][s-1];
}else if(dp[i][j][s-1]==ansv){
ansp+=way[i][j][s-1];
}
}
printf("%I64d %I64d\n",ansv==-1?0:ansv,ansp/2);
}
return 0;
}

poj 2288 Islands and Bridges_状态压缩dp_哈密尔顿回路问题的更多相关文章

  1. poj 2288 Islands and Bridges——状压dp(哈密尔顿回路)

    题目:http://poj.org/problem?id=2288 不知为什么记忆化搜索就是WA得不得了! #include<iostream> #include<cstdio> ...

  2. poj - 3254 - Corn Fields (状态压缩)

    poj - 3254 - Corn Fields (状态压缩)超详细 参考了 @外出散步 的博客,在此基础上增加了说明 题意: 农夫有一块地,被划分为m行n列大小相等的格子,其中一些格子是可以放牧的( ...

  3. POJ 1691 Painting a Board(状态压缩DP)

    Description The CE digital company has built an Automatic Painting Machine (APM) to paint a flat boa ...

  4. POJ 1632 Vase collection【状态压缩+搜索】

    题目传送门:http://poj.org/problem?id=1632 Vase collection Time Limit: 1000MS   Memory Limit: 10000K Total ...

  5. poj 3311 floyd+dfs或状态压缩dp 两种方法

    Hie with the Pie Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6436   Accepted: 3470 ...

  6. poj 2411 Mondriaan's Dream_状态压缩dp

    题意:给我们1*2的骨牌,问我们一个n*m的棋盘有多少种放满的方案. 思路: 状态压缩不懂看,http://blog.csdn.net/neng18/article/details/18425765 ...

  7. POJ 3254 Corn Fields(状态压缩)

    一道状态压缩的题,错了好多次....应该先把满足的情况预处理出来 #include<iostream> #include<cstdio> #include<cstring ...

  8. POJ 2441 Arrange the Bulls 状态压缩递推简单题 (状态压缩DP)

    推荐网址,下面是别人的解题报告: http://www.cnblogs.com/chasetheexcellence/archive/2012/04/16/poj2441.html 里面有状态压缩论文 ...

  9. POJ 1753 Flip Game (状态压缩 bfs+位运算)

    Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 square ...

随机推荐

  1. 揭开枚举类的面纱(Unlocking the Enumeration/enum Mystery)

    枚举给用户定义固定数据组提供了方便.枚举类就是一系列常量整型值,这也就意味着枚举类型不能被修改. 这里我们将要讨论C语言中枚举类型的用法和限制. 枚举通过枚举关键值定义,类似结构体定义 语法(Synt ...

  2. 关于maven-jetty-plugin 自动重启问题

    <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin ...

  3. c语言for语句

    首先呢 for语句是由4部分组成 for(表达式1;表达式2;表达式3) 循环体: 注意 1:循环中的表达式用;隔开 表达式1通常用来呢赋初值 表达式2通常用来循环控制也就是循环条件 表达式3通常就是 ...

  4. 第34讲 UI组件之 ProgressDialog和Message

    第34讲UI组件之 ProgressDialog和Message 1.进度对话框 ProgressDialog <1>简介 ProgressDialog是AlertDialog类的一个扩展 ...

  5. Android Studio新手全然指引

    Android Studio新手全然指引 @author ASCE1885的 Github 简书 微博 CSDN Android Studio的下载及安装 假设你的电脑能够FQ,那么请直接到Andro ...

  6. Android开发之DatePickerDialog与TimePickerDialog的功能和使用方法具体解释

    DatePickerDialog与TimePickerDialog的功能比較简单,使用方法也非常easy.仅仅要以下两步就可以. Ø  通过newkeyword创建DatePickerDialog.T ...

  7. 20个经典bootsrtap后台html站点模板推荐

    今天为大家推荐20款不同风格的Bootstrap后台管理模板,每一款都经典可用,能预览和下载,保证让你挑得眼花缭乱. 1,Simpli flag蓝色 Simpli Flat蓝色管理模板是一款採用Fla ...

  8. poj 3009 Curling 2.0 (dfs )

    Curling 2.0 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11879   Accepted: 5028 Desc ...

  9. Ubuntu 10.04下安装Opengl glx

    1.安装OpenGL Library sudo apt-get install build-essential 2. 安装OpenGL Utilities sudo apt-get install l ...

  10. IPMITOOL常用操作指令

    一.开关机,重启 1. 查看开关机状态: ipmitool -H (BMC的管理IP地址) -I lanplus -U (BMC登录用户名) -P (BMC 登录用户名的密码) power statu ...