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[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_哈密尔顿回路问题的更多相关文章
- poj 2288 Islands and Bridges——状压dp(哈密尔顿回路)
题目:http://poj.org/problem?id=2288 不知为什么记忆化搜索就是WA得不得了! #include<iostream> #include<cstdio> ...
- poj - 3254 - Corn Fields (状态压缩)
poj - 3254 - Corn Fields (状态压缩)超详细 参考了 @外出散步 的博客,在此基础上增加了说明 题意: 农夫有一块地,被划分为m行n列大小相等的格子,其中一些格子是可以放牧的( ...
- POJ 1691 Painting a Board(状态压缩DP)
Description The CE digital company has built an Automatic Painting Machine (APM) to paint a flat boa ...
- POJ 1632 Vase collection【状态压缩+搜索】
题目传送门:http://poj.org/problem?id=1632 Vase collection Time Limit: 1000MS Memory Limit: 10000K Total ...
- poj 3311 floyd+dfs或状态压缩dp 两种方法
Hie with the Pie Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 6436 Accepted: 3470 ...
- poj 2411 Mondriaan's Dream_状态压缩dp
题意:给我们1*2的骨牌,问我们一个n*m的棋盘有多少种放满的方案. 思路: 状态压缩不懂看,http://blog.csdn.net/neng18/article/details/18425765 ...
- POJ 3254 Corn Fields(状态压缩)
一道状态压缩的题,错了好多次....应该先把满足的情况预处理出来 #include<iostream> #include<cstdio> #include<cstring ...
- POJ 2441 Arrange the Bulls 状态压缩递推简单题 (状态压缩DP)
推荐网址,下面是别人的解题报告: http://www.cnblogs.com/chasetheexcellence/archive/2012/04/16/poj2441.html 里面有状态压缩论文 ...
- 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 ...
随机推荐
- redis 学习笔记二 (简单动态字符串)
redis的基本数据结构是动态数组 一.c语言动态数组 先看下一般的动态数组结构 struct MyData { int nLen; char data[0]; }; 这是个广泛使用的常见技巧,常用来 ...
- pyqt一个小例子
# -*- coding: utf-8 -*- __author__ = 'Administrator' from PyQt4 import Qt,QtCore,QtGui import sys,ra ...
- Javascript: 截取字符串多出来并用省略号[...]显示
/背景知识/ substring 方法用于提取字符串中介于两个指定下标之间的字符 substring(start,end) 开始和结束的位置,从零开始的索引 参数描述 start 必需.一个非负的整数 ...
- iphone开发之适配iphone5
iphone5出来了,从不用适配的我们也要像android一样适配不同分辨率的屏幕了. 公司产品新版本需要适配iphone5,经过一番折腾算是搞定了.下面分享给大家: iphone5的屏幕分辨 ...
- Android 之 Shape (圆角输入框)
1 简介 本文主要介绍通过 shape 来设置 EditText 的圆角. 2 shape 的设置 shape_life_search.xml 放在 res/drawable 文件夹内 < ...
- spark1.1.0学习路线
经过一段时间授课,积累下不少的spark知识.想逐步汇总成资料,分享给小伙伴们.对于想视频学习的小伙伴,能够訪问炼数成金站点的<spark大数据平台>课程.每周的课程是原理加实 ...
- Network 20Q--Q2 How does Google sell ad spaces?
在使用Google搜索的时候会发现,搜索出来的页面除了在左边显示搜索结果以外,还会页面的右边推荐一些广告.那么Google是怎么从这些广告挣钱以及广告商可以通过Google广告获得什么利益呢? Goo ...
- 关于SetCapture() 和 ReleaseCapture()的使用方法
查MSND,对SetCapture()函数的说明为:“该函数在属于当前线程的指定窗体里设置鼠标捕获.一旦窗体捕获了鼠标,全部鼠标输入都针对该窗体,不管光标是否在窗体的边界内.同一时刻仅仅能有一个窗体捕 ...
- Some good iOS questions
这里,我列举了一些在Stackoverflow中一些比较好的关于iOS的问题.大部分我列举的问题都是关于Objective C.所有问题中,我比较喜欢“为什么”这一类型的问题. 问题 1. What’ ...
- MySQL Replication Error 处理一例
故障现象 MySQL slave status详情 mysql> show slave status\G *************************** 1. row ********* ...