poj 2288 哈密顿路 状压dp
2016-02-26 17:36
253 查看
题目:http://poj.org/problem?id=2288
题意:给出了n个地点和m座桥(连接顶点的),画出哈密尔顿圈并求出最大值,他们的最大值由三部分决定,1:n个地点的value值之和,2:顶点之间连接之积,3:三个(连续的)顶点之积;要求输出最大值,并且存在最大值的情况总数,同时,对于两个完全逆向的路径可以认为是同一条路径;
分析:发现每个点的状态由前面两个点确定,用DP(S,A,B)表示状态为S时,当前到达A,而上一个点是B时的最大得分,这个状态由DP(S',B,C)通过从B走到A得到,S'=S-(1<<A),即S'状态就是经过B和C但不经过A的一个状态,C是不同于A和B的一个点。
【状态转移】dp[S][A][B] =max(dp[S][A][B],dp[S'][B][C]+temp) 这里的temp指的是加上的得分即Vb*Va+Va,如果构成三角关系(即A和C间有边),temp就要再加上Vb*Va*Vc.
【边界条件】DP((1<<A)+(1<<B),A,B)=Va+Vb+Va*Vb(A和B间有边)表示
参考博客:点击打开链接
题意:给出了n个地点和m座桥(连接顶点的),画出哈密尔顿圈并求出最大值,他们的最大值由三部分决定,1:n个地点的value值之和,2:顶点之间连接之积,3:三个(连续的)顶点之积;要求输出最大值,并且存在最大值的情况总数,同时,对于两个完全逆向的路径可以认为是同一条路径;
分析:发现每个点的状态由前面两个点确定,用DP(S,A,B)表示状态为S时,当前到达A,而上一个点是B时的最大得分,这个状态由DP(S',B,C)通过从B走到A得到,S'=S-(1<<A),即S'状态就是经过B和C但不经过A的一个状态,C是不同于A和B的一个点。
【状态转移】dp[S][A][B] =max(dp[S][A][B],dp[S'][B][C]+temp) 这里的temp指的是加上的得分即Vb*Va+Va,如果构成三角关系(即A和C间有边),temp就要再加上Vb*Va*Vc.
【边界条件】DP((1<<A)+(1<<B),A,B)=Va+Vb+Va*Vb(A和B间有边)表示
参考博客:点击打开链接
#include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; ll f[1<<14][14][14],way[1<<14][14][14]; bool edge[14][14]; ll v[14]; int main() { int n,m,T; // freopen("f.txt","r",stdin); scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&v[i]); if(n==1){ printf("%d 1\n",v[1]);continue; } memset(edge,0,sizeof(edge)); int a,b; while(m--){ scanf("%d%d",&a,&b); edge[a][b]=edge[b][a]=1; } memset(f,-1,sizeof(f)); memset(way,0,sizeof(way)); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ //边界初始化 if(i==j||!edge[i][j])continue; int ii=1<<(i-1),jj=1<<(j-1); ll tmp=v[i]+v[j]+v[i]*v[j]; f[ii+jj][i][j]=tmp; way[ii+jj][i][j]=1; //cout<<tmp<<endl; } } for(int s=0;s<(1<<n);s++){ for(int i=1;i<=n;i++){ if(!(s&(1<<(i-1))))continue; for(int j=1;j<=n;j++){ if(!(s&(1<<(j-1)))||i==j||!edge[i][j])continue; for(int k=1;k<=n;k++){ if(!(s&(1<<(k-1)))||i==k||j==k||!edge[j][k])continue; int ts=s-(1<<(i-1)); if(f[ts][j][k]==-1)continue; ll tmp=v[i]+v[i]*v[j]+f[ts][j][k]; if(edge[i][k])tmp+=v[i]*v[j]*v[k]; //如果可以形成三角形 if(f[s][i][j]<tmp){ //如果有更大的值,那么更新,方法数目way也直接由上一条路决定 f[s][i][j]=tmp; way[s][i][j]=way[ts][j][k]; } else if(tmp==f[s][i][j])way[s][i][j]+=way[ts][j][k]; //如果相等,way求和 } } } } ll ans=-1,num=0; int p=(1<<n)-1; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i==j)continue; if(ans<f[p][i][j]){ ans=f[p][i][j];num=way[p][i][j]; } else if(ans==f[p][i][j])num+=way[p][i][j]; } } if(ans==-1){ printf("0 0\n");continue; } printf("%lld %lld\n",ans,num/2); //因为计算的和f[p][i][j]==f[p][j][i]都加进去了,所以/2 } return 0; }
相关文章推荐
- 五年北京,这个改变我命运的城市,终于要离开了
- IDEA_Debug_checks references injected by intellilang plugin
- 算法导论—Boyer-Moore(BM)算法
- 黑客帝国效果
- 创建环境使用的存储过程
- Spark MLlib 1.6 -- 聚类
- jQuery基础知识之选择器
- 关于aspx 页面生成html 源码顶部空行不得不说的事儿
- ios runtime(1)
- 在Nodejs中贯彻单元测试
- oracle数据库imp导入报错IMP-00002
- 在MyEclipse中安装SVN插件subclipse
- hive使用小结
- Spring中@Autowired注解、@Resource注解的区别
- 在Eclipse中管理Java类引用的技巧
- poj 1151 Atlantis && codeforces #337 D. Vika and Segments (线段树+扫描线)(求面积并)
- 二叉搜索树
- OkHttp3源码分析
- [BZOJ1076] [SCOI2008]奖励关
- Ripsaw EV2 Extreme Luxury Super Tank 2015