题目链接:http://poj.org/problem?id=2288

题目:

题意:求Hamilton 路径权值的最大值,且求出有多少条权值这么大的Hamilton路径。

思路:状压dp,dp[i][j][k]表示第i种状态下倒数第二个岛屿为j倒数第一个岛屿为k下的权值,cnt[i][j][k]记录条数。

  当有边(i,j)存在时,有如下初值可赋:
  d[(1<<i)+(1<<j)][i][j]=val[i]+val[j]+val[i]*val[j],cnt[(1<<i)+(1<<j)][i][j]=1。
  
如果状态(state,i,j)可达,检查岛k,如果此时k没有被访问过并且有边(j,k)存在,则做如下操作:
  1)设tmp为下一步访问岛k时获得的总利益,r=state+(1<<k)。
  2)如果tmp>d[r][j][k],表示此时可以更新到更优解,则更新:
      d[r][j][k]=tmp,cnt[r][j][k]=cnt[state][i][j]。
  3)如果tmp==d[r][j][k],表示此时可以获得达到局部最优解的更多方式,则更新:
      cnt[r][j][k]+=cnt[state][i][j]。
  最后检查所有的状态((1<<n)-1,i,j),叠加可以得到最优解的道路数。
  需要注意的是,题目约定一条路径的两种行走方式算作一种,所以最终结果要除2。

代码实现如下:

 #include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<int, ll> pil;;
typedef pair<int, int> pii;
typedef unsigned long long ull; #define lson i<<1
#define rson i<<1|1
#define bug printf("*********\n");
#define FIN freopen("D://code//in.txt", "r", stdin);
#define debug(x) cout<<"["<<x<<"]" <<endl;
#define IO ios::sync_with_stdio(false),cin.tie(0); const double eps = 1e-;
const int mod = ;
const int maxn = (<<) + ;
const double pi = acos(-);
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f; int t, n, m, u, v;
int w[], mp[][];
ll dp[maxn][][], cnt[maxn][][]; int main() {
//FIN;
scanf("%d", &t);
while(t--) {
memset(mp, , sizeof(mp));
memset(dp, -, sizeof(dp));
memset(cnt, , sizeof(cnt));
scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++i) {
scanf("%d", &w[i]);
}
for(int i = ; i <= m; ++i) {
scanf("%d%d", &u, &v);
mp[u][v] = mp[v][u] = ;
}
if(n == ) {
printf("%d 1\n", w[]);
continue;
}
for(int i = ; i <= n; ++i) {
for(int j = ; j <= n; ++j) {
if(i != j && mp[i][j]) {
dp[(<<(i-))|(<<(j-))][i][j] = w[i] + w[j] + (ll) w[i] * w[j];
cnt[(<<(i-))|(<<(j-))][i][j] = ;
}
}
}
int tot = << n;
for(int i = ; i < tot; ++i) {
for(int j = ; j <= n; ++j) {
if(i & (<<(j-))) {
for(int k = ; k <= n; ++k) {
if(j != k && (i & (<<(k-))) && mp[j][k] && dp[i][j][k] != -) {
for(int x = ; x <= n; ++x) {
if(j != x && k != x && mp[k][x] && (i & (<<(x-))) == ) {
ll tmp = dp[i][j][k] + w[x] + (ll)w[k] * w[x];
if(mp[j][x]) tmp += (ll)w[k] * w[j] * w[x];
if(tmp > dp[i|(<<(x-))][k][x]) {
dp[i|(<<(x-))][k][x] = tmp;
cnt[i|(<<(x-))][k][x] = cnt[i][j][k];
} else if(tmp == dp[i|(<<(x-))][k][x]){
cnt[i|(<<(x-))][k][x] += cnt[i][j][k];
}
}
}
}
}
}
}
}
ll ans1 = , ans2 = ;
for(int i = ; i <= n; ++i) {
for(int j = ; j <= n; ++j) {
if(i == j) continue;
if(dp[tot-][i][j] > ans1) {
ans1 = dp[tot-][i][j];
ans2 = cnt[tot-][i][j];
} else if(dp[tot-][i][j] == ans1) {
ans2 += cnt[tot-][i][j];
}
}
}
printf("%lld %lld\n", ans1, ans2 / );
}
return ;
}

Islands and Bridges(POJ2288+状压dp+Hamilton 回路)的更多相关文章

  1. POJ 2288 Islands and Bridges (状压DP,变形)

    题意: 给一个无向图,n个点m条边,每个点有点权,要求找到一条哈密顿路径,使得该路径的f(path)值最大.输出f值,若有多条最大f值的路径,输出路径数量. f值由如下3点累加而来: (1)所有点权之 ...

  2. poj 2288 Islands and Bridges (状压dp+Tsp问题)

    这道题千辛万苦啊! 这道题要涉及到当前点和前面两个点,那就设dp[state][i][j]为当前状态为state,当前点为i,前一个点为j 这个状态表示和之前做炮兵那题很像,就是涉及到三个点时,就多设 ...

  3. POJ 2288 Islands and Bridges(状压DP)题解

    题意:n个点,m有向边,w[i]表示i的价值,求价值最大的哈密顿图(只经过所有点一次).价值为:所有点的w之和,加上,每条边的价值 = w[i] * w[j],加上,如果连续的三个点相互连接的价值 = ...

  4. POJ 2288 Islands and Bridges(状压dp)

    http://poj.org/problem?id=2288 题意: 有n个岛屿,每个岛屿有一个权值V,一条哈密顿路径C1,C2,...Cn的值为3部分之和: 第1部分,将路径中每个岛屿的权值累加起来 ...

  5. CH0103最短Hamilton路径 & poj2288 Islands and Brigdes【状压DP】

    虐狗宝典学习笔记: 取出整数\(n\)在二进制表示下的第\(k\)位                                                    \((n >> ...

  6. 最短Hamilton路径(状压dp)

    最短Hamilton路径实际上就是状压dp,而且这是一道作为一个初学状压dp的我应该必做的题目 题目描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 ...

  7. AcWing 最短Hamilton距离 (状压DP)

    题目描述 给定一张 n 个点的带权无向图,点从 0∼n−1 标号,求起点 0 到终点 n−1 的最短 Hamilton 路径. Hamilton 路径的定义是从 0 到 n−1 不重不漏地经过每个点恰 ...

  8. 状压DP天秀

    状压DP,依靠的是把状态用某种压缩方式表示出来进而DP,大多数时候是二进制状压. 直接看例题吧. 一双木棋     九尾狐吃棉花糖     islands and bridges 愤怒的小鸟   芯片 ...

  9. CF11D A Simple Task(状压DP)

    \(solution:\) 思路大家应该都懂: 状压DP:\(f[i][j]\),其中 \(i\) 这一维是需要状压的,用来记录19个节点每一个是否已经走过(走过为 \(1\) ,没走为 \(0\) ...

随机推荐

  1. 软件工程个人作业3——集大通APP案例分析

    第一部分:调研, 评测 1.第一次上手体验 主要界面截图: 感受: 1.界面不美观: 2.特色功能展现模块不突出,以上截图为打开APP所看到的界面展示,但是这些功能都不是该APP的特色功能,显得有些累 ...

  2. mysql有索引和无索引的查询速度对比

    演示100万级数据有索引和无索引的情况下的查找速度:

  3. Android Studio -导入项目 gradle处理

    如果导入 android studio 项目, 那么一定要注意 需要合适的gradle版本,具体方法为: 首先导入步骤: 打开android studio ==> File ==> New ...

  4. apache server-status配置

    引言 自己配置LAMP服务器时(xwamp),获取状态信息出现错误: You don't have permission to access /server-status on this server ...

  5. 下载文件 通过a 标签 请求某个servlet进行下载的

    下载文件 通过a 标签 请求某个servlet进行下载的

  6. hadoop和spark搭建记录

    因玩票需要,使用三台搭建spark(192.168.1.10,192.168.1.11,192.168.1.12),又因spark构建在hadoop之上,那么就需要先搭建hadoop.历经一个两个下午 ...

  7. 洛谷P3656 展翅翱翔之时 (はばたきのとき)(洛谷2017.3月赛round1 t4)

    题目背景 船が往くよミライへ旅立とう 船只启航 朝未来展开旅途 青い空笑ってる(なにがしたい?) 湛蓝天空露出微笑(想做些什么?) ヒカリになろうミライを照らしたい 化作光芒吧 想就此照亮未来 輝きは ...

  8. LCA的倍增算法

    LCA,即树上两点之间的公共祖先,求这样一个公共祖先有很多种方法: 暴力向上:O(n) 每次将深度大的点往上移动,直至二者相遇 树剖:O(logn) 在O(2n)预处理重链之后,每次就将深度大的沿重链 ...

  9. SCOI2014极水的题解- -

    话说SCOI都考了1个月了,终于拿出决心把题解补完了,但都说了是极水的题解,大家就看着玩吧- - DAY1 T1:目标是找最长不降子序列,先就有一个比较显然的结论,就是假如我们要拔高区间[L, R], ...

  10. word----遇到问题-----word中插入的图片无法左对齐----格式按钮为灰色

    当我们在用word时,有时要插入图片,却发现,插入的图片只在中间位置,不能拖到左边,这时怎么办呢 主要是图层的高低原因导致的不能拖动. 这个时候我们只需要设置一下图片的图层类型即可. 对着图片右键在设 ...