P1278(单词游戏 dfs完成状压dp状态的转移)

题目
P1278(单词游戏 dfs完成状压dp状态的转移)_第1张图片
dp[i][S]:当前状态S下选的最后一个单词为i,还可以最多填充多少+单词i本身的长度。
所以dp[now][S]=max(dp[now][S],dp[i][S|(1<<(i-1))+len[i]] (单词i可以在单词now的前面)。
由于dp第一维是没有顺序的,所以我们用dfs来完成状压dp的过程。
if(dp[now][S]==-1) dp[now][S]这个值已经得到正确的了无需继续更新。
dfs的过程是索取转移状态的,用来更新当前状态。

#include
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
const int N=16+2,M=100+5;
char s[N][M];int len[N];
int dp[N][1<<N],n;
int dfs(int now,int S){
    if(dp[now][S]!=-1) return dp[now][S];
    dp[now][S]=len[now];
    for(int i=1;i<=n;++i)
        if(s[now][1]==s[i][len[i]]&&!(S&(1<<(i-1)))) dp[now][S]=max(dp[now][S],dfs(i,S|(1<<(i-1)))+len[now]);
    return dp[now][S];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%s",s[i]+1),len[i]=strlen(s[i]+1);
    m(dp,-1);int ans=0;
    for(int i=1;i<=n;++i) ans=max(ans,dfs(i,1<<(i-1)));
    printf("%d\n",ans);
}
#include
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
const int N=16+2,M=100+5;
char s[N][M];int len[N],dp[1<<N][N],A[N],B[N];
int main(){
    int n,t;scanf("%d",&n),t=1<<n;
    for(int i=1;i<=n;++i) scanf("%s",s[i]+1),len[i]=strlen(s[i]+1);
    for(int i=1;i<=n;++i) dp[1<<(i-1)][i]=len[i];
    for(int i=1;i<t;++i){
        int o1=0,o2=0;
        for(int j=1;j<=n;++j) (i&(1<<j-1))?(A[++o1]=j):(B[++o2]=j);
        for(int j=1;j<=o1;++j) for(int k=1;k<=o2;++k){
            int u=A[j],v=B[k];
            if(s[u][len[u]]==s[v][1]) dp[i|(1<<(v-1))][v]=max(dp[i|(1<<(v-1))][v],dp[i][u]+len[v]);
        }
    }
    int ans=0;
    for(int i=1;i<t;++i) for(int j=1;j<=n;++j) ans=max(ans,dp[i][j]);
    printf("%d\n",ans);
}

你可能感兴趣的:(DP==状压dp)