题目链接

题目描述:哈密尔顿路问题。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. Codeforce 217 div2

    C 假设每种颜色的个数都相同,可以用轮换的方式,让答案达到最大n,当不同的时候,可以每次从每种颜色中取出相同个数的手套来操作; 一直迭代下去直到只剩下1种颜色; 再将这一种颜色与之前交换过的交换就行了 ...

  2. pyqt记录内容(音乐播放器)

    #这是UI文件 # -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'AudioPlayerDia ...

  3. python StringIO标准库基础学习

    #标准库:StringIO提供类文件API文本缓冲区#作用:可以处理内存中的文本,有2种不同的实现:cStringIP版本用c编写提高速度,StringIO用python来提供可移植性,与其他字符串连 ...

  4. C++11 静态断言(static_assert)

      简介 C++0x中引入了static_assert这个关键字,用来做编译期间的断言,因此叫做静态断言. 其语法很简单:static_assert(常量表达式,提示字符串). 如果第一个参数常量表达 ...

  5. sql 读取excel中的数据

    select 列名 as 字段名 from openBowSet('MSDASQL.1','driver=Microsoft Excel Driver(*.xls);dbq=文件存放地址','sele ...

  6. C#中的一些复习。

    摘自http://www.cnblogs.com/yuchengping/p/3151537.html 等日后自己来完善. 基本概念 1..NET是平台,C#是.NET上的一门语言. 2.C#的异常处 ...

  7. Asp.Net HttpApplication请求管道与Session(二)

    Asp.Net 回话的创建与结束 LogHelper.LogHelper _log = new LogHelper.LogHelper(); /// <summary> /// 程序开始- ...

  8. UI基础视图----UIScrollView总结

    UIScrollView是UIKit框架下的很重要的视图类,是UIView的子类.UILabel,UIImageView,UIWebView分别用于展示文字,图片,网页,UILabel通过属性text ...

  9. C#调用进程

    Process process = new Process(); process.StartInfo.FileName = "123.exe"; process.StartInfo ...

  10. JavaScript的数据类型转换

    首先,由于JavaScript是弱类型语言(弱类型的语言的东西没有明显的类型,他能随着环境的不同,自动变换类型而强类型则没这样的规定,不同类型间的操作有严格定义,只有相同类型的变量才能操作,虽然系统也 ...