poj-1699-Best Sequence-dfs+子状态

这道题目竟然真的ac了,好神奇啊。

当时算的时间复杂度为O(T*N!),理论值达到7kw。

做法:

预处理dp数组,使得dp[i][j]代表j放在i后面长度的增加值。

然后dfs,dfs的时候要注意,用一个二进制数标记当前状态。

二进制中0代表当前位置已取,1代表当前位置未取。每次查找二进制的子状态。

然后看看哪个位置在子状态消失了。

一定要直接查找子状态。

查找方法详参我的另一篇博客:http://blog.csdn.net/rowanhaoa/article/details/16370215

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
char str[31][31];
int dp[31][31];
int vis[31];
int n;
int ans;
int fc[(1<<21)];
int houji(int x,int y)
{
    int i,j;
    int len1=strlen(str[x]);
    int len2=strlen(str[y]);
    for(i=0;i<len1;i++)
    {

        if(str[x][i]==str[y][0])
        {
            for(j=0;j<len2&&i+j<len1;j++)
            {
                if(str[x][i+j]!=str[y][j])break;
            }
            if(j==len2||i+j==len1)break;
        }
    }
    int anss=len2-(len1-i);
    if(anss<=0)vis[y]=1;
    return anss;
}
void chu()
{
    int i,j;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=n;j++)
        {
            if(i==j||vis[i]||vis[j])continue;
            dp[i][j]=houji(i,j);
        }
    }
}
void dfs(int x,int len,int tai)
{
    //cout<<x<<" "<<len<<" "<<tai<<endl;
    tai=tai-(1<<(x-1));
    int leap=0;
    int ts;
    ts=tai;
    while(tai)
    {
        int bb;
        bb=(tai-1)&tai;
        int y=tai-bb;
        y=fc[y];
        y++;
        tai=tai-(1<<(y-1));
        dfs(y,len+dp[x][y],ts);
        leap=1;
    }
    if(leap==0)ans=min(ans,len);
}
int main()
{
    int T,i,j;
    j=1;
    for(i=0;i<21;i++)
    {
        fc[j]=i;
        j=j*2;
    }
    for(j=1;j<(1<<21);j++)
    {
        if(fc[j]==0)fc[j]=fc[j-1];
    }
    scanf("%d",&T);
    while(T--)
    {
        ans=99999999;
        memset(vis,0,sizeof(vis));
        scanf("%d",&n);
        for(i=1;i<=n;i++)scanf("%s",str[i]);
        chu();
        int ss=(1<<n)-1;
        for(i=1;i<=n;i++)
            if(vis[i])ss-=(1<<(i-1));
        int ll=0;
        for(i=1;i<=n;i++)
        {
            if(vis[i]==0)dfs(i,strlen(str[i]),ss);
        }
        cout<<ans<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值