poj 2288 Islands and Bridges——状压dp(哈密尔顿回路)
题目:http://poj.org/problem?id=2288
不知为什么记忆化搜索就是WA得不得了!
#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; }
改成刷表就可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; }