Islands and Bridges(POJ 2288状压dp)

题意:给你一个图和每个点的价值,边权值为连接两点权值的积,走哈密顿通路,若到达的点和上上个点相连则价值加三点乘积,求哈密顿通路的最大价值,和最大价值哈密顿通路的条数。

分析:开始看这个题很吓人,但想想这个题状态好确定dp[i][j][k]表示 i已走过点的情况,当前点为j前一点为k所产生的最大价值,枚举所有可行的情况即可,接着想怎么求条数啊,

纠结了好久,才发现和在求价值时若和原来的价值相等,则加原来状态所包含的条数,若更新了最大值,这数量为当前状态的条数,还要注意两条完全反向的路径看成一条路径。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <complex>
#include <cassert>
#include <utility>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
#define lson l,m,rt<<1
#define pi acos(-1.0)
#define rson m+1,r,rt<<11
#define All 1,N,1
#define read freopen("in.txt", "r", stdin)
#define N 1<<13
const ll  INFll = 0x3f3f3f3f3f3f3f3fLL;
const int INF= 0x7ffffff;
const int mod =  1000000007;
int n,m,con[15][15],v[15];
ll dp[N][15][15],num[N][15][15];
void solve(){
    memset(dp,-1,sizeof(dp));
    memset(num,0,sizeof(num));
    int cas=(1<<n)-1;
    dp[0][0][0]=0;
    for(int i=1;i<=n;++i){
        dp[1<<(i-1)][0][i]=v[i];
        num[1<<(i-1)][0][i]=1;
    }
    for(int i=1;i<=cas;++i){
        for(int j=1;j<=n;++j){
        if(!(i&(1<<(j-1))))continue;
        for(int k=0;k<=n;++k){
        if(j==k)continue;
        if(k==0&&!(i&(1<<(j-1)))||k!=0&&!(i&(1<<(k-1))))continue;
        if(dp[i][k][j]==-1)continue;
        for(int l=1;l<=n;++l){
            if(!(i&(1<<(l-1)))&&con[j][l]){
                int t=i+(1<<(l-1));
                ll tot=v[l]*(v[j]+1);
                if(con[l][k])
                    tot+=v[k]*v[j]*v[l];
                tot+=dp[i][k][j];
                if(dp[t][j][l]<tot){
                   dp[t][j][l]=tot;
                   num[t][j][l]=num[i][k][j];
                }
                else if(dp[t][j][l]==tot){
                    num[t][j][l]+=num[i][k][j];
                }
            }
        }
    }
    }
    }
    ll maxv=-1,sum=0;
    for(int i=0;i<=n;++i)
        for(int j=0;j<=n;++j)
        maxv=max(maxv,dp[cas][i][j]);
    if(maxv==-1)
    printf("0 0\n");
    else{
    for(int i=0;i<=n;++i)
    for(int j=0;j<=n;++j)
    if(maxv==dp[cas][i][j])
    sum+=num[cas][i][j];
    printf("%I64d %I64d\n",maxv,sum/2?sum/2:1);
    }
}
int main()
{
    int q;
    scanf("%d",&q);
    while(q--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
            scanf("%d",&v[i]);
        int x,y;
        memset(con,0,sizeof(con));
        while(m--){
            scanf("%d%d",&x,&y);
            con[x][y]=1;
            con[y][x]=1;
        }
        solve();
    }
return 0;
}

  

时间: 2024-11-25 20:56:26

Islands and Bridges(POJ 2288状压dp)的相关文章

POJ 1038 状压DP

一个公司生产一种2*3规模的芯片,但是原材料上面有一些地方是不能用来当作芯片材料的,给出原料大小,及上面不能做原料的点,问你怎么分解,可以使生成芯片最大化. 对M进行三进制状压 last数组存储第i-1行和i-2行状态,cur数组存储i行和i-1行状态 cur[k]=2; // 本行k位置和上行k位置都不可用 cur[k]=1; // 本行k位置可用,上行k位置不可用 cur[k]=0; // 本行和上行位置k均可用 必须用滚动数组,否则爆内存 #include "stdio.h" #

POJ 3254 (状压DP) Corn Fields

基础的状压DP,因为是将状态压缩到一个整数中,所以会涉及到很多比较巧妙的位运算. 我们可以先把输入中每行的01压缩成一个整数. 判断一个状态是否有相邻1: 如果 x & (x << 1) 非0,说明有相邻的两个1 判断一个状态能否放在该行: 如果 (a[i] & state) != state,说明是不能放置的.因为a[i]中存在某个0和对应state中的1,与运算之后改变了state的值 判断相邻两行的状态是否有同一列相邻的1: 如果(state & _state)不

Best Sequence(poj 1699) 状压dp(TSP)

类似于前两天做的那个wordstack.状压的其实有时候爆搜+记忆化也差不多. 就是这个是要与之前的都重合,移位预处理要注意. 理解好第一个样例就行 /* *********************************************** Author :bingone Created Time :2014/12/9 22:48:56 File Name :a.cpp ************************************************ */ #inclu

POJ 3254 状压DP

题目大意: 一个农民有一片n行m列 的农场   n和m 范围[1,12]  对于每一块土地 ,1代表可以种地,0代表不能种. 因为农夫要种草喂牛,牛吃草不能挨着,所以农夫种菜的每一块都不能有公共边. 告诉你 n ,m 和那些地方能种菜哪些地方不能种菜,求农夫一共有多少种方案种菜 解法: 基本思想是状压 也就是用一个int 型的数代表一行的种菜策略,二进制的0代表该位不能种菜,1位代表能种菜,使用位运算使处理速度变快 对于单行行,最多有2^12 种情况,并且 2^12种情况里面还有很多不满足题意的

POJ 2411 状压DP经典

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 16771   Accepted: 9683 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

POJ 2686(状压DP

第一次做状压感觉那一长串for显示了这是个多么暴力的算法呢...1A了倒是挺顺的 #include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<utility> #include<vector> #include<cstring> #include<cmath> #define INF 0x3fffffff #d

DP:Islands and Bridges(POJ 2288)

2015-09-21 造桥基建工程 题目大意,就是有n座岛和k座桥,要你找一条哈密顿圈(找完所有的岛,并且每个岛只经过一次),当经过一座岛就加上岛的价值,如果两岛联通,则加上两座岛的价值之积,如果三座岛之间构成三角联通,则再加上三岛之积,问最大价值的哈密顿圈和最大价值和哈密顿圈的个数 哈密顿圈是是一个NP完全的问题,用DP就可以解决这个问题,现在的问题就是,怎么解决呢? 首先我们要明确,这一题要用DP做什么,首先这一题的最后肯定要求到最后岛全部都通过的情况,然后还需要保留前两个岛的信息 那么这个

poj 3254 状压dp入门题

1.poj 3254  Corn Fields    状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相邻,求有多少种放法. #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #d

poj 2923 状压dp+01背包

好牛b的思路 题意:一系列物品,用二辆车运送,求运送完所需的最小次数,两辆车必须一起走 解法为状态压缩DP+背包,本题的解题思路是先枚举选择若干个时的状态,总状态量为1<<n,判断这些状态集合里的那些物品能否一次就运走,如果能运走,那就把这个状态看成一个物品.预处理完能从枚举中找到tot个物品,再用这tol个物品中没有交集(也就是两个状态不能同时含有一个物品)的物品进行01背包,每个物品的体积是state[i],价值是1,求包含n个物品的最少价值也就是dp[(1<<n)-1](dp