Pieces(hdu4628,状态压缩的动态规划)

41 篇文章 0 订阅
41 篇文章 0 订阅

http://acm.hdu.edu.cn/showproblem.php?pid=4628

Pieces

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 536    Accepted Submission(s): 317

Problem Description

You heart broke into pieces.My string broke into pieces.But you will recover one day,and my string will never go back.

Given a string s.We can erase a subsequence of it if this subsequence is palindrome in one step. We should take as few steps as possible to erase the whole sequence.How many steps do we need?

For example, we can erase abcba from axbyczbea and get xyze in one step.

Input

The first line contains integer T,denote the number of the test cases. Then T lines follows,each line contains the string s (1<= length of s <= 16).

T<=10.

Output

For each test cases,print the answer in a line.

Sample Input

2

aa

abb

Sample Output

1

2

Source

2013 Multi-University Training Contest 3

Recommend

zhuyuanchen520

解析:

题意:给出一个字符串,要求最少需要多少步可以将其删完。其中回文序列可以一次性删掉

思路:

状态压缩的动态规划:

由于数据比较小,所以可以暴力枚举每一种状态然后判断其合法性。

最后用状态转移方程解决即可

562MS 1196K 862 B G++

dp[i]=min(dp[i],dp[i-j]+1);表示i状态下的最小步数,ji的合法子集;

步骤:

1,枚举每一种状态并记录其合法性

2.在状态转移方程中更新值

仿标称写的

*/

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=1<<16+1;
int inf=10000000;
char ch[maxn];
int dp[maxn],can[maxn];
int min(int a,int b){return a<b? a:b;}
void work()
{   int i,j,ok,n,k;
     int s,t;
scanf("%s",ch);
n=strlen(ch);
for(i=0;i<(1<<n);i++)//枚举每一种状态并且记录其合法性
{  char temp[maxn];
    k=0;
for(j=0;j<n;j++)//举出在i状态下的情形
if(i>>j&1)
temp[k++]=ch[j];
ok=1;
for(s=0,t=k-1;t>s;t--,s++)//判断该状态是否合法,即是否是回文字
{if(temp[s]!=temp[t])
   {
   	ok=0;
   	break;
   }
}
can[i]=ok;
}
dp[0]=0;
for(i=1;i<(1<<n);i++)
{  dp[i]=inf;
for(j=i;j>0;(--j)&=i)//枚举j状态下的子集
{
if(can[j])//如果该子集合法则列入方程计算
{dp[i]=min(dp[i],dp[i-j]+1);
}
}
}
printf("%d\n",dp[(1<<n)-1]);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{  memset(dp,0,sizeof(dp));
work();
}
return 0;
}
/*
1187MS	66084K	1347 B	G++
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cassert>
using namespace std;
typedef long long int64;
const int MAX_N = 16, INF = ~0U >> 2;
int n;
int dp[1 << MAX_N][MAX_N][MAX_N]; //rest,i,j
char s[MAX_N + 1];
void work() {
scanf("%s", s);
n = strlen(s);
for (int i = 0; i < n; ++i) {
for (int j = i; j < n; ++j) {
dp[0][i][j] = 0;//初始化为0
}
}
for (int rest = 1; rest < (1 << n); ++rest) {
for (int i = n - 1; i >= 0; --i) {
for (int j = i; j < n; ++j) {
//rest,i,j
int&ret = dp[rest][i][j] = INF;//rest表示i与j之间的状态
if (i < j)
ret = min(dp[rest][i + 1][j], dp[rest][i][j - 1]);
if (s[i] == s[j] && (rest >> i & 1) && (rest >> j & 1)) {//当第i个字符状态和第j的字符状态1
int nrest = rest & (~(1 << i)) & (~(1 << j));//将i和j位置0
if (nrest == 0)//若此时状态为全0,即此状态将字符串都删除了
ret = min(ret, dp[nrest][i][j] + 1);
else
ret = min(ret, dp[nrest][i][j]);
}
}
}
for (int i = n - 1; i >= 0; --i) {
for (int j = i; j < n; ++j) {
dp[rest][i][j] = min(dp[rest][i][j], dp[rest][0][n - 1] + 1);
}
}
}
cout << dp[(1 << n) - 1][0][n - 1] << endl;
}
int main() {
int T;
cin >> T;
while (T--) {
work();
}
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值