poj2288 状压dp
2017-08-08 10:16
393 查看
传送门
题意:有n个点,m条边,每个点有一个权值,求一条哈密顿回路,但是权值计算不同,包括三部分:1,经过的所有点的权值相加。2,经过的连续两个点的权值的乘积。3,能够构成三角型的连续三个点的乘积。这些全部加起来就是这条回路的总权值。输出最大权值和这个最大权值的路线有多少条。
状压dp,由于当前位置只和前两个点的位置有关,所以我们用dp[s][i][j],表示从i走到了j,目前倒数第二走到的是i,倒数第一走到的是j,目前走过的岛的状态集合是s(其二进制表示状态,0<=s<=(1<<13)-1,最多13个岛)的权值,ways[s][i][j]表示路径的条数。
首先把已知的边的权值算出来,
很好理解,第一个地点走i岛,第二个地点走j岛,状态就是用’或’表示,权值就是val[i]+val[j]+val[i]*val[j],满足两个相连的点嘛,加上自身值再加上乘积。
然后我们就可以枚举了,我们倒数第一个点在j,倒数第二个点在i,那么如果有一条路径j->k,并且k还没走过呢(状态s里没有第k个岛,即s的二进制第k位为0),我们就从j走到k,下面分两种情况;
1,k与i点不可直达,
2,k可以直达i,
因为我们要求最大值,所以赋值之前比较一下,比之前大才更新,并同时更新ways[s|k][j][k],如果相等的话,我们就只更新ways,
最后遍历一遍所有状态s为“n个1”(
ans1更新权值,ans2更新路径条数
AC代码:
题意:有n个点,m条边,每个点有一个权值,求一条哈密顿回路,但是权值计算不同,包括三部分:1,经过的所有点的权值相加。2,经过的连续两个点的权值的乘积。3,能够构成三角型的连续三个点的乘积。这些全部加起来就是这条回路的总权值。输出最大权值和这个最大权值的路线有多少条。
状压dp,由于当前位置只和前两个点的位置有关,所以我们用dp[s][i][j],表示从i走到了j,目前倒数第二走到的是i,倒数第一走到的是j,目前走过的岛的状态集合是s(其二进制表示状态,0<=s<=(1<<13)-1,最多13个岛)的权值,ways[s][i][j]表示路径的条数。
首先把已知的边的权值算出来,
for(int i=0; i<n; i++) for(int j=0; j<n; j++) { if(Map[i][j]) { dp[(1<<i)|(1<<j)][i][j]=val[i]+val[j]+val[i]*val[j]; ways[(1<<i)|(1<<j)][i][j]=1; } }
很好理解,第一个地点走i岛,第二个地点走j岛,状态就是用’或’表示,权值就是val[i]+val[j]+val[i]*val[j],满足两个相连的点嘛,加上自身值再加上乘积。
然后我们就可以枚举了,我们倒数第一个点在j,倒数第二个点在i,那么如果有一条路径j->k,并且k还没走过呢(状态s里没有第k个岛,即s的二进制第k位为0),我们就从j走到k,下面分两种情况;
1,k与i点不可直达,
dp[s|(1<<k)][j][k]=dp[s][i][j]+val[k]+val[k]*val[j]
2,k可以直达i,
dp[s|(1<<k)][j][k]=dp[s][i]j] + val[k] + val[j] * val[k] + val[i] * val[j] * val[k];
因为我们要求最大值,所以赋值之前比较一下,比之前大才更新,并同时更新ways[s|k][j][k],如果相等的话,我们就只更新ways,
ways[s|(1<<k)][j][k]+=ways[s][i][j];
最后遍历一遍所有状态s为“n个1”(
s=(1<<n)-1)的dp[s][i][j]值,选择最大的即可,
int s=(1<<n)-1; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { if(Map[i][j]) { if(dp[s][i][j]>ans1) { ans1=dp[s][i][j]; ans2=ways[s][i][j]; } else if(dp[s][i][j]==ans1) ans2+=ways[s][i][j]; } } }
ans1更新权值,ans2更新路径条数
AC代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=13;
LL dp[(1<<N)]
,ways[(1<<N)]
;
LL val
;
int Map
;
void solve(int n)
{
memset(dp,-1,sizeof(dp));
memset(ways,0,sizeof(ways));
for(int i=0; i<n; i++) for(int j=0; j<n; j++) { if(Map[i][j]) { dp[(1<<i)|(1<<j)][i][j]=val[i]+val[j]+val[i]*val[j]; ways[(1<<i)|(1<<j)][i][j]=1; } }
for(int s=0; s<(1<<n); s++)
{
for(int i=0; i<n; i++)
if(s&(1<<i))///s包含第i个岛
{
for(int j=0; j<n; j++)
if(s&(1<<j)&&Map[i][j]&&dp[s][i][j]!=-1)///s包含第j个岛,且dp不为-1,且i-j有路径
{
for(int k=0; k<n; k++) ///寻找j到k的路径
if(Map[j][k]&&!(s&(1<<k)))///s不包含k岛,但是j到k有路径,所以我们要走一走
{
LL temp = dp[s][i][j]+val[k]+val[k]*val[j];///单纯的走到k的权值保存一下
if(Map[k][i])///k能到i的话形成三角
{
temp+=val[i]*val[j]*val[k];
}
if(dp[s|(1<<k)][j][k]<temp)
{
dp[s|(1<<k)][j][k]=temp;
ways[s|(1<<k)][j][k]=ways[s][i][j];
}
else if(dp[s|(1<<k)][j][k]==temp)
{
ways[s|(1<<k)][j][k]+=ways[s][i][j];
}
}
}
}
}
}
int main()
{
int T,n,m;
int u,v;
cin>>T;
while(T--)
{
cin>>n>>m;
memset(Map,0,sizeof(Map));
for(int i=0; i<n; i++)
cin>>val[i];
for(int i=0; i<m; i++)
{
cin>>u>>v;
u--;
v--;
Map[u][v]=Map[v][u]=1;
}
if(n==1)
{
printf("%lld 1\n",val[0]);
continue;
}
solve(n);
LL ans1,ans2;
ans1=ans2=0;
int s=(1<<n)-1; for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { if(Map[i][j]) { if(dp[s][i][j]>ans1) { ans1=dp[s][i][j]; ans2=ways[s][i][j]; } else if(dp[s][i][j]==ans1) ans2+=ways[s][i][j]; } } }
cout<<ans1<<" "<<ans2/2<<endl;
}
return 0;
}
/**
2
3 3
2 2 2
1 2
2 3
3 1
4 6
1 2 3 4
1 2
1 3
1 4
2 3
2 4
3 4
*/
相关文章推荐
- 状态压缩DP总结【POJ3254】【POJ1185】【POJ3311】【HDU3001】【POJ2288】【ZOJ4257】【POJ2411】【HDU3681】
- poj 2430 Lazy Cows 状压dp
- POJ 3254 Corn Fields 矬到荼蘼的状压DP
- 2014 Super Training #1 B Fix 状压DP
- zoj3471Most Powerful 状压dp
- hdu 1185 状压dp 好题 (当前状态与上两行有关系)
- hlg2130一笔画【状压dp】
- 【 状压DP】 [UVA10817] Headmaster's Headache
- POJ 3311 Hie with the Pie (Floyd + 状压dp 简单TSP问题)
- BZOJ3590【状压DP】
- LightOJ 1011 Marriage Ceremonies【状压DP】
- 状态压缩DP总结【POJ3254】【POJ1185】【POJ3311】【HDU3001】【POJ2288】【ZOJ4257】【POJ2411】【HDU3681】
- hdoj3001Travelling【状压dp 类TSP】
- POJ 3254 Corn Fields (状压DP,轮廓线DP)
- poj 3797 Tiling a Grid With Dominoes 状压dp
- CF543C 让所有的串成为独特的串的最小代价(状压dp,贪心)
- HDU 3681 Prison Break - 状压dp【TSP】
- 【BZOJ3590】[Snoi2013]Quare【双连通分量】【状压DP】【神题】
- POJ 3254 状压dp
- [状压DP] Codeforces Beta Round #72 Div1 E Two Subsequences