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;

}

  

 

你可能感兴趣的:(bridge)