POJ 2288 Islands and Bridge 状压DP

题意:有n(n<=13)座小岛,有个人要旅游全部的小岛,每个岛有权值,设当前走到的岛的权值为c,上个岛为b,上上个岛为a,那么ans+=c+c*b+a*b*c(如果当前岛和上上岛连通)
思路:
先枚举一下边界条件,然后就是正常的跑状态,一定要注意状态是从小跑到大的,所以我们此时的状态只能用到比自己的状态小的状态
n==1的时候要特判

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long LL;
#define maxn 14
#define f(x) (x*1.0)
#define inf 0x3f3f3f3f
#define maxm maxn*maxn
#define lowbit(x) (x&(-x))
#define cheak(i) printf("%d ",i)
#define lson(x) (splay[x].son[0])
#define rson(x) (splay[x].son[1])
#define rfor(i,a,b) for(i=a;i<=b;++i)
#define lfor(i,a,b) for(i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define mec(a,b) memcpy(a,b,sizeof(b))
int A[maxn];
bool Map[maxn][maxn];
LL dp[1<<maxn][maxn][maxn];
LL path[1<<maxn][maxn][maxn];
int main()
{
    int n,m,i,j,k,T,u,v;
    scanf("%d",&T);
    while(T--)
    {
        mem(Map,false);
        scanf("%d%d",&n,&m);
        rfor(i,1,n) scanf("%d",&A[i]);
        rfor(i,1,m)
        {
            scanf("%d%d",&u,&v);
            Map[u][v]=Map[v][u]=true;
        }
        if(n==1)
        {
            printf("%d 1\n",A[1]);
            continue;
        }

        mem(dp,-1);mem(path,0);
        rfor(i,1,n)
         rfor(j,1,n)
         if(i!=j&&Map[i][j])//枚举边界状态 
         {
            int state1=(1<<(i-1));
            int state2=(1<<(j-1));
            LL tmp=A[i]+A[j]+A[i]*A[j];
            dp[state1+state2][i][j]=tmp;
            path[state1+state2][i][j]=1;
        }

        int state;
        rfor(state,0,(1<<(n))-1)
        {
            rfor(i,1,n)
            {
                if(state&(1<<(i-1)))
                rfor(j,1,n)
                {
                    if(state&(1<<(j-1))&&Map[i][j]&&i!=j)
                    rfor(k,1,n)
                    if(state&(1<<(k-1))&&Map[j][k]&&i!=k&&j!=k)
                    {
                        int state1=state-(1<<(i-1));
                        if(dp[state1][j][k]==-1) continue;
                        LL tmp=A[i]+A[i]*A[j]+dp[state1][j][k];
                        if(Map[i][k]) tmp+=A[i]*A[j]*A[k];
                        if(tmp>dp[state][i][j])
                        {
                            dp[state][i][j]=tmp;
                            path[state][i][j]=path[state1][j][k];
                        }
                        else if(tmp==dp[state][i][j])
                        path[state][i][j]+=path[state1][j][k];
                    }
                }
            }
        }
        state=(1<<(n))-1;
        LL ans=-1,num=0;
        rfor(i,1,n)
         rfor(j,1,n)
         {
            if(dp[state][i][j]>ans)
            {
                ans=dp[state][i][j];
                num=path[state][i][j];
            }
            else if(dp[state][i][j]==ans)
            num+=path[state][i][j];
        }
        if(ans==-1) printf("0 0\n"); 
        else printf("%lld %lld\n",ans,num/2);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值