POJ 2817 状压DP&&记忆化搜索

68 篇文章 0 订阅

这个题的意思是第一行给出case数N (1 <= N <= 10),然后给出N个单词,每个一行,当输入不是正整数的时候结束。每个单词最多10个字母。要求的是,按任意顺序排列这些单词,可以在单词前面加任意个空格,使得相邻的单词上下对应的字母数目最多,并输出最多是多少。

先预处理出每两个单词相连所能对应的字母数最多的情况,记录到match[i][j]中。注意在一个单词前面加空格时不能使该单词长度超过另一个,WA了一次。

一共最多10个单词,状压存储状态,然后记忆化搜索即可


#include "stdio.h"
#include "string.h"
int n;
char str[20][20];
int match[20][20];
int dp[1<<15][20];
int index[20];
int Max(int a,int b)
{
    if (a<b) return b;
    else return a;
}

void cal_match(int a,int b)
{
    int i,j,max,sum;
    max=0;

    for (i=0;str[a][i];i++)
    {
        sum=0;
        for (j=0;str[b][j];j++)
            if((i+j<strlen(str[a])) && (str[a][i+j]==str[b][j])) sum++;
        max=Max(max,sum);
    }

    for (i=0;str[b][i];i++)
    {
        sum=0;
        for (j=0;str[a][j];j++)
            if((i+j<strlen(str[b])) && (str[b][i+j]==str[a][j])) sum++;
        max=Max(max,sum);
    }
    match[a][b]=match[b][a]=max;
}

int dfs(int aim,int x)
{
    int i,sum,status;
    status=aim^index[x];
    if (status==0) return 0;
    if (dp[aim][x]!=-1) return dp[aim][x];

    sum=0;
    for (i=1;i<=n;i++)
    {
        if ((status&index[i])>0) sum=Max(sum,dfs(status,i)+match[x][i]);
    }
    dp[aim][x]=sum;
    return sum;
}

int main()
{
    int ans,aim,i,j;
    while (scanf("%d",&n)!=EOF)
    {
        if (n<=0) break;
        for (i=1;i<=n;i++)
            scanf("%s",str[i]);
        memset(match,0,sizeof(match));

        for (i=1;i<=n;i++)
            for (j=1;j<=n;j++)
            if (i!=j)
            cal_match(i,j);

        aim=0;
        memset(dp,-1,sizeof(dp));
        for (i=1;i<=n;i++)
        {
            index[i]=1<<(i-1);
            dp[index[i]][i]=0;
            aim+=index[i];
        }
        ans=0;

        for (i=1;i<=n;i++)
            ans=Max(ans,dfs(aim,i));
        printf("%d\n",ans);

    }
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值