Islands and Bridges(POJ2288+状压dp+Hamilton 回路)
题目链接: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 回路)的更多相关文章
- POJ 2288 Islands and Bridges (状压DP,变形)
题意: 给一个无向图,n个点m条边,每个点有点权,要求找到一条哈密顿路径,使得该路径的f(path)值最大.输出f值,若有多条最大f值的路径,输出路径数量. f值由如下3点累加而来: (1)所有点权之 ...
- poj 2288 Islands and Bridges (状压dp+Tsp问题)
这道题千辛万苦啊! 这道题要涉及到当前点和前面两个点,那就设dp[state][i][j]为当前状态为state,当前点为i,前一个点为j 这个状态表示和之前做炮兵那题很像,就是涉及到三个点时,就多设 ...
- POJ 2288 Islands and Bridges(状压DP)题解
题意:n个点,m有向边,w[i]表示i的价值,求价值最大的哈密顿图(只经过所有点一次).价值为:所有点的w之和,加上,每条边的价值 = w[i] * w[j],加上,如果连续的三个点相互连接的价值 = ...
- POJ 2288 Islands and Bridges(状压dp)
http://poj.org/problem?id=2288 题意: 有n个岛屿,每个岛屿有一个权值V,一条哈密顿路径C1,C2,...Cn的值为3部分之和: 第1部分,将路径中每个岛屿的权值累加起来 ...
- CH0103最短Hamilton路径 & poj2288 Islands and Brigdes【状压DP】
虐狗宝典学习笔记: 取出整数\(n\)在二进制表示下的第\(k\)位 \((n >> ...
- 最短Hamilton路径(状压dp)
最短Hamilton路径实际上就是状压dp,而且这是一道作为一个初学状压dp的我应该必做的题目 题目描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 ...
- AcWing 最短Hamilton距离 (状压DP)
题目描述 给定一张 n 个点的带权无向图,点从 0∼n−1 标号,求起点 0 到终点 n−1 的最短 Hamilton 路径. Hamilton 路径的定义是从 0 到 n−1 不重不漏地经过每个点恰 ...
- 状压DP天秀
状压DP,依靠的是把状态用某种压缩方式表示出来进而DP,大多数时候是二进制状压. 直接看例题吧. 一双木棋 九尾狐吃棉花糖 islands and bridges 愤怒的小鸟 芯片 ...
- CF11D A Simple Task(状压DP)
\(solution:\) 思路大家应该都懂: 状压DP:\(f[i][j]\),其中 \(i\) 这一维是需要状压的,用来记录19个节点每一个是否已经走过(走过为 \(1\) ,没走为 \(0\) ...
随机推荐
- C 语言疑难杂症 [转:http://blog.chinaunix.net/uid-20688544-id-1894880.html]
无聊在网上找了些C语言的东东练一下手,竟然发现其实还有好多细节之前,没注意到,该好好复习一下先. 解决掉的问题先不发出来,把疑问的先做个笔记,过几天解决了就回来修改补上. #include < ...
- PHP中类和对象
面向对象中的基本概念 类和对象 对象: 万物皆对象: 类: 任何对象,都可以人为“规定”为某种类型(类别): class Person{ var $name ; var $age; var ...
- python脚本批量生成50000条插入数据的sql语句
f = open("xx.txt",'w') for i in range(1,50001): str_i = str(i) realname = "lxs"+ ...
- Ajax修改全局变量问题解决方法(Zepto版)
前两天项目遇到一个用ajax修改全局变量的案例,一开始无法给这个全局变量修改赋值,在网上查了一下,解决如下: 修改前: var word=1; $.ajax({ url:"myJSON.js ...
- Idea报错Command line is too long
需要在该项目文件夹下.idea/workspace.xml中添加 <component name="PropertiesComponent"> ... <prop ...
- 【bzoj5197】[CERC2017]Gambling Guide 期望dp+堆优化Dijkstra
题目描述 给定一张n个点,m条双向边的无向图. 你要从1号点走到n号点.当你位于x点时,你需要花1元钱,等概率随机地买到与x相邻的一个点的票,只有通过票才能走到其它点. 每当完成一次交易时,你可以选择 ...
- windows200364位iis6 php环境搭建
最近接一个小活,就是帮着部署个php网站,服务器是window2003,iis6.之前在我自己得服务器上已经搭建过php环境,区别是我的服务器windows2012,而对方的是windows 2003 ...
- Period UVALive - 3026(next数组)
题意: 给出一个长度不超过1000000的字符串S, 对于该字符串的所有前缀求其周期, 如果周期K >= 2输出起始位置是第几个字符和其周期K 解析: 先求next数组 对于每一个位置如果i % ...
- Linux内核分析第一周学习博客 --- 通过反汇编方式学习计算机工作过程
Linux内核分析第一周学习博客 通过反汇编方式学习计算机工作过程 总结: 通过这次对一个简单C程序的反汇编学习,我了解到计算机在实际工作工程中要涉及大量的跳转指针操作.计算机通常是顺序执行一条一条的 ...
- Yii2 数据库基本操作
//1.简单查询 $admin=Admin::model()->findAll($condition,$params); $admin=Admin::model()->findAll( ...