POJ--2288--Islands and Bridges(状态压缩DP+bfs)

介绍

通过图G经过所有的节点,且所有的节点仅经过一次的通路,就是哈密顿通路。

题意

有N座岛,M座桥,让你找到一条哈密顿通路,当经过一座岛就加上该岛的价值,如果相邻两岛之间有桥再加上两岛价值之积,如果相邻三岛之间两两都有桥,再加上三岛价值之积。求最大总价值是多少以及达到最大总价值的路径有几条。

思路
这道题还算一个比较中规中矩的状压DP入门题。就是得设计两个状态转移方程,所以有写麻烦。

两个状态转移方程都是代表在这次选了j节点上次选了k节点而达到了 i+sta[j] 状态。dp_v 用来存该情况下最大总价值,dp_n用来存达到同种情况下的达到最大总价值的方案数。

dp_v[i+sta[j]][j][k]=max(dp_v[i][k][z]+V(经过这个点所带的总价值));

dp_n[i+sta[j]][j][k]+=dp[i][k][z];

注意:N==1时;用__int64保存;T组数据;方案数除以2。

代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#include<queue>
using namespace std;
int sta[15]= {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};
__int64 dp_n[1<<13][13][13];
__int64 dp_v[1<<13][13][13];
bool flag[1<<13][13][13];//入队列时进行标记,否则会造成重复入队列,会超内存
int N,M,val[15],g[15][15];
__int64  ans_1,ans_2;
struct node
{
    short i,j,k;
};

void init()//初始化
{
    memset(g,0,sizeof(g));
    memset(dp_n,0,sizeof(dp_n));
    memset(dp_v,-1,sizeof(dp_v));
    memset(flag,0,sizeof(flag));
}
queue<node>q;
void solve()
{
    node temp;
    for(int i=0; i<N; ++i)
    {
        temp.i=sta[i];
        temp.j=i;
        temp.k=i;
        flag[temp.i][temp.j][temp.k]=1;
        dp_n[temp.i][temp.j][temp.k]=1;
        dp_v[temp.i][temp.j][temp.k]=val[i];
        q.push(temp);

    }
    while(!q.empty())
    {
        int i=q.front().i;
        int j=q.front().j;
        int k=q.front().k;
        flag[i][j][k]=0;
        q.pop();
        for(int z=0; z<N; ++z)
        {
            if(g[j][z]&&((i&sta[z])==0))
            {
                temp.i=i+sta[z];
                temp.j=z;
                temp.k=j;
                __int64 temp_v;
                temp_v=dp_v[i][j][k]+val[z]+val[z]*val[j];
                if(g[z][k]&&k!=j)
                        temp_v+=val[z]*val[j]*val[k];
                if(dp_v[temp.i][temp.j][temp.k]==temp_v)
                {
                    dp_n[temp.i][temp.j][temp.k]+=dp_n[i][j][k];
                    if(temp.i<sta[N]-1&&flag[temp.i][temp.j][temp.k]==0)
                    {
                        q.push(temp);
                        flag[temp.i][temp.j][temp.k]=1;
                    }
                }
                if(dp_v[temp.i][temp.j][temp.k]<temp_v)
                {
                    dp_v[temp.i][temp.j][temp.k]=temp_v;
                    dp_n[temp.i][temp.j][temp.k]=dp_n[i][j][k];
                    if(temp.i<sta[N]-1&&flag[temp.i][temp.j][temp.k]==0)
                    {
                        q.push(temp);
                        flag[temp.i][temp.j][temp.k]=1;
                    }
                }
            }
        }
    }
    for(int j=0; j<N; ++j)
    {
        for(int k=0; k<N; ++k)
        {
            if(dp_v[sta[N]-1][j][k]!=-1)
            {
                temp.i=sta[N]-1;
                temp.j=j;
                temp.k=k;
                if(ans_1<dp_v[temp.i][temp.j][temp.k])
                {
                    ans_1=max(ans_1, dp_v[temp.i][temp.j][temp.k]);
                    ans_2=0;
                    ans_2=dp_n[temp.i][temp.j][temp.k];
                }
                else if(ans_1==dp_v[temp.i][temp.j][temp.k])
                    ans_2+=dp_n[temp.i][temp.j][temp.k];
            }
        }
    }
    if(N==1)//当N为1时特殊处理
        ans_2=2;
    printf("%I64d %I64d
",ans_1,ans_2/2);//因为不算顺序,正反一样,所以应该除2,
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&N,&M);
        int v,x,y;
        for(int i=0; i<N; ++i)
        {
            scanf("%d",&val[i]);
        }
        for(int i=0; i<M; ++i)
        {
            scanf("%d%d",&x,&y);
            --x;
            --y;
            g[x][y]=1;
            g[y][x]=1;
        }
        ans_1=0;
        ans_2=0;
        solve();
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/l1l1/p/8608794.html