poj 2288

传送门

解题思路

状压dp,记录路径条数,dp[S][i][j]表示状态为S,前一个点是i,再前一个点是j的最大值,然后在开个一样的数组记录方案数,时间复杂度O(2^n*n^2),注意要用long long,还有数据有一个点的情况。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define int long long

using namespace std;
const int N = 14;
typedef long long LL;
const int inf = -0x3f3f3f3f;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

int q,n,m,a[N][N],val[N];
LL dp[1<<N][N][N],num[1<<N][N][N],ans,ans_num;

signed main(){
    q=rd();
    while(q--){
        ans=0,ans_num=0;
        memset(a,0,sizeof(a));
        memset(dp,-0x3f,sizeof(dp));
        memset(num,0,sizeof(num));
        n=rd(),m=rd();register int x,y;
        for(register int i=1;i<=n;i++) val[i]=rd();
        for(register int i=1;i<=m;i++) {
            x=rd(),y=rd();
            a[x][y]=a[y][x]=1;
        }
        dp[0][0][0]=0;num[0][0][0]=1;
        for(register int i=0;i<(1<<n)-1;i++)
            for(register int j=1;j<=n;j++)if(!((1<<j-1)&i))
                for(register int k=0;k<=n;k++)if(((1<<k-1)&i && a[j][k]) || k==0)
                    for(register int p=0;p<=n;p++)if(((1<<p-1)&i && a[p][k]) || p==0){
                        if(dp[i][k][p]==-inf) continue;
                        LL now=dp[i][k][p]+val[j]+(LL)val[j]*val[k];
                        if(a[j][p]) now+=(LL)val[j]*val[k]*val[p];
                        if(dp[i|(1<<j-1)][j][k]==now)
                            num[i|(1<<j-1)][j][k]+=num[i][k][p];
                        else if(dp[i|(1<<j-1)][j][k]<now){
                            dp[i|(1<<j-1)][j][k]=now;
                            num[i|(1<<j-1)][j][k]=num[i][k][p];
                        }
                    }
        for(register int i=1;i<=n;i++)
            for(register int j=1;j<=n;j++)  
                if(a[i][j]) {
                    if(dp[(1<<n)-1][i][j]>ans) {ans=dp[(1<<n)-1][i][j];ans_num=num[(1<<n)-1][i][j];}
                    else if(dp[(1<<n)-1][i][j]==ans) ans_num+=num[(1<<n)-1][i][j]; 
                }
        if(n==1 && m==0) {ans=val[1];ans_num=2;}
        cout<<ans<<" "<<ans_num/2<<endl;
    }
    return 0;
}
posted @ 2018-09-16 14:50  Monster_Qi  阅读(148)  评论(0编辑  收藏  举报