poj 2282 Islands and Bridges(状压DP)

n个点,m条无向边,问是否存在哈密顿路,若存在,最大的边权和是多少?与之对应的路的条数有多少条?
边权和的计算方法:所有顶点的权值+相邻顶点权值的乘积
若相邻三个点两两之间都有边,则还需加上它们的权值的乘积

考虑用一个二进制位表示某个顶点是否被访问。用n个二进制位表示一个状态。
注意到,每一个状态和前一个走过的顶点以及上上个走过的顶点有关。
因此,设dp[s][i][j]表示在状态s下,经过顶点j,到达顶点i的最大权值。
那么状态转移方程:

dp[s][i][j]=max(dp[s][i][j],dp[s][j][k]+a[i]+a[i]a[j]+tmp)

说明:s’为上一个状态,i为当前枚举的要到达的顶点,j为前一个状态已经到达的顶点,k为上上个走过的顶点。a[i]表示顶点i的权值,若i、j、k两两之间都由边,则tmp=a[i]*a[j]*a[k],否则tmp=0。

初始化:首先初始化为-1,表示未定义。然后枚举两个顶点i,j。dp[s][i][j]=a[i]+a[j]+a[i]*a[j]。s=2^(i-1)+2^(j-1)

对于路径条数的统计,同样地,设num[s][i][j]表示在状态s下经过j到达i的路径条数。在更新dp的同时,更新num即可。

注意:
1、数据会超出int的范围。
2、只有1个顶点的情况。
3、当最终dp的值为-1时,说明不存在哈密顿路,输出0 0。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
#define maxn 14
typedef __int64 LL;
bool Map[maxn][maxn];
LL a[maxn],dp[1<<13][maxn][maxn],num[1<<13][maxn][maxn];
int main()
{
    int q,n,m,i,j,k,s;
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;++i) scanf("%I64d",&a[i]);
        memset(Map,0,sizeof(Map));
        for(i=0;i<m;++i)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            Map[x][y]=Map[y][x]=1;
        }
        if(n==1) {printf("%I64d 1\n",a[1]); continue;}
        memset(dp,-1,sizeof(dp));
        for(i=1;i<=n;++i)
            for(j=1;j<=n;++j)
                if(Map[i][j]){
                    num[(1<<(i-1))+(1<<(j-1))][i][j]=1;
                    dp[(1<<(i-1))+(1<<(j-1))][i][j]=a[i]+a[j]+a[i]*a[j];
                }
        for(s=0;s<(1<<n);++s)
            for(i=1;i<=n;++i)
                if(s&(1<<(i-1)))
                    for(j=1;j<=n;++j)
                    {
                        if(!Map[j][i]) continue;
                        if(s&(1<<(j-1)))
                        {
                            for(k=1;k<=n;++k)
                            {
                                if(!Map[j][k]) continue;
                                if(k==i) continue;
                                if(s&(1<<(k-1)))
                                {
                                    if(dp[s-(1<<(i-1))][j][k]==-1) continue;
                                    LL tmp=dp[s-(1<<(i-1))][j][k]+a[i]+a[i]*a[j];
                                    if(Map[i][k]) tmp+=a[i]*a[j]*a[k];
                                    if(dp[s][i][j]<tmp)
                                    {
                                        dp[s][i][j]=tmp;
                                        num[s][i][j]=num[s-(1<<(i-1))][j][k];
                                    }
                                    else if(dp[s][i][j]==tmp)
                                        num[s][i][j]+=num[s-(1<<(i-1))][j][k];
                                }
                            }
                        }
                    }
        LL ans=-1,cnt;
        for(i=1;i<=n;++i)
            for(j=1;j<=n;++j)
                if(ans<dp[(1<<n)-1][i][j])
                {
                    ans=dp[(1<<n)-1][i][j];
                    cnt=num[(1<<n)-1][i][j];
                }
                else if(ans==dp[(1<<n)-1][i][j]) cnt+=num[(1<<n)-1][i][j];

        if(ans!=-1) printf("%I64d %I64d\n",ans,cnt>>1);
        else puts("0 0");
    }
    return 0;
}

你可能感兴趣的:(poj 2282 Islands and Bridges(状压DP))