题目:http://poj.org/problem?id=2288

不知为什么记忆化搜索就是WA得不得了!

poj 2288 Islands and Bridges——状压dp(哈密尔顿回路)_#definepoj 2288 Islands and Bridges——状压dp(哈密尔顿回路)_#define_02
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=20,Lm=(1<<13)+5;
int q,n,m,lm,v[N];
ll ans,prn,dp[Lm][N][N],f[Lm][N][N];
bool b[N][N];
ll dfs(int S,int x,int px)
{
    if(dp[S][x][px]!=-1)return dp[S][x][px];
    if(S==lm){f[S][x][px]=1;return dp[S][x][px]=0;}
    for(int i=1;i<=n;i++)
        if(b[x][i]&&(S&(1<<(i-1)))==0)
        {
            int D=(S|(1<<(i-1)));
            ll w=dfs(D,i,x)+v[i]+v[x]*v[i]+(b[px][i]?v[px]*v[x]*v[i]:0);
            if(w>dp[S][x][px])
                dp[S][x][px]=w,f[S][x][px]=f[D][i][x];
            else if(w==dp[S][x][px])
                f[S][x][px]+=f[D][i][x];
        }
    return dp[S][x][px];
}
int main()
{
    scanf("%d",&q);
    while(q--)
    {
        memset(b,0,sizeof b);
        scanf("%d%d",&n,&m);lm=(1<<n)-1;
        for(int i=1;i<=n;i++)scanf("%d",&v[i]);
        int x,y;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);b[x][y]=1;b[y][x]=1;
        }
        if(n==1){printf("%d 1\n",v[1]);continue;}//
        memset(dp,-1,sizeof dp);memset(f,0,sizeof f);
        ans=-1;prn=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(b[i][j])
                {
                    int D=((1<<(i-1))|(1<<(j-1)));//注意括号! 
                    ll w=dfs(D,i,j)+v[i]*v[j]+v[i]+v[j];
                    if(w>ans)ans=w,prn=f[D][i][j];
                    else if(w==ans)prn+=f[D][i][j]; 
                }
        printf("%I64d %I64d\n",prn?ans:0,prn>>1);//
    }
    return 0;
}
View Code

改成刷表就可A了。注意初始化一遍,然后开始dp,而不是一边初始化一边dp很多次。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=20,Lm=(1<<13)+5;
int T,n,m,c[N],lm;
ll dp[Lm][N][N],f[Lm][N][N],ans,prn;
bool b[N][N];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        memset(b,0,sizeof b);
        scanf("%d%d",&n,&m);lm=(1<<n)-1;
        for(int i=1;i<=n;i++)scanf("%d",&c[i]);
        int x,y;
        while(m--)
        {
            scanf("%d%d",&x,&y);
            b[x][y]=b[y][x]=1;
        }
        if(n==1){printf("%d 1\n",c[1]);continue;}
        memset(dp,-1,sizeof dp);memset(f,0,sizeof f);
        for(int u=1;u<=n;u++) for(int v=1;v<=n;v++) if(b[u][v])
        {
            int s=((1<<(u-1))|(1<<(v-1)));
            dp[s][u][v]=c[u]+c[v]+c[u]*c[v];
            f[s][u][v]=1;
        }
        for(int s=3;s<=lm;s++)
            for(int i=1;i<=n;i++) if(s&(1<<(i-1)))
                for(int j=1;j<=n;j++) if(dp[s][i][j]!=-1)
                    for(int k=1;k<=n;k++) if(b[i][k]&&!(s&(1<<(k-1))))
                    {
                        int d=(s|(1<<(k-1)));
                        ll w=dp[s][i][j]+c[k]+c[i]*c[k]+(b[j][k]?c[i]*c[j]*c[k]:0);
                        if(dp[d][k][i]<w)
                        {
                            dp[d][k][i]=w;
                            f[d][k][i]=f[s][i][j];
                        }
                        else if(dp[d][k][i]==w)
                            f[d][k][i]+=f[s][i][j];
                    }
        ans=-1;prn=0;//因为有"prn?" 
        for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(dp[lm][i][j]!=-1)
            if(dp[lm][i][j]>ans)ans=dp[lm][i][j],prn=f[lm][i][j];
            else if(dp[lm][i][j]==ans)prn+=f[lm][i][j];
        printf("%I64d %I64d\n",prn?ans:0,prn>>1);
    }
    return 0;
}