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;
}

  

 

posted on 2015-07-24 16:59  积跬步、至千里  阅读(126)  评论(0编辑  收藏  举报

导航