您的位置:首页 > 其它

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

2013-08-16 21:33 363 查看
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状态下的最小步数,j是i的合法子集;

步骤:

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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: