您的位置:首页 > 其它

ACM: uva 11584 -

2016-05-19 23:28 351 查看
Problem H: Partitioning by Palindromes
We say a sequence of characters is
palindromeif it is the same written
forwards and backwards. For example, 'racecar' is a palindrome, but
'fastcar' is not.




partition of a sequence
of characters is a list of one or more disjoint non-empty groups of
consecutive characters whose concatenation yields the initial
sequence. For example, ('race', 'car') is a partition of 'racecar'
into two groups.
Given a sequence of characters, we can always
create a partition of these characters such that each group in the
partition is a palindrome! Given this observation it is natural to
ask: what is the minimum number of groups needed for a given string
such that every group is a palindrome?
For example:
'racecar' is already a palindrome, therefore it can be
partitioned into one group.

'fastcar' does not contain any non-trivial palindromes, so it
must be partitioned as ('f', 'a', 's', 't', 'c', 'a', 'r').

'aaadbccb' can be partitioned as ('aaa', 'd', 'bccb').

Input begins with the
number n of test cases.
Each test case consists of a single line of between 1 and 1000
lowercase letters, with no whitespace within.
For each test case, output a line containing the
minimum number of groups required to partition the input into
groups of palindromes.
Sample Input
3
racecar
fastcar
aaadbccb
Sample Output
1
7
3
 

题意: 将一段字符串划分为尽可能少的回文串, 输出最少能划分为多少个回文串.

 

解题思路:

     
1. 简单DP, 最朴素的做法就是枚举起点和终点, 判断这段是否为回文串, 时间复杂度O(n^3);

         方程: 
dp[i] = min(dp[i], dp[j-1]+1) 
(j->i是回文串);

        
dp[i]表示: 前i个字符最少可以组成多少个回文串.

     
2. 还有方法可以缩小时间复杂度, 就是直接判断j->i是否是回文串, 时间复杂度O(n^2);

        
可以设flag[i][j]: 以str[j]开始的长度为i的字符串是否为回文串.

 

代码:

O(n^3)

#include <cstdio>

#include <iostream>

#include <cstring>

using namespace std;

#define MAX 1005

const int INF = (1<<29);

int n;

int dp[MAX];

char str[MAX];

inline int min(int a, int b)

{

 return a < b ? a : b;

}

bool judge(int left, int right)

{

 for(int i = left, j = right; i <=
j; ++i, --j)

  if( str[i] != str[j] ) return
false;

 return true;

}

int main()

{

// freopen("input.txt", "r", stdin);

 scanf("%d", &n);

 int i, j;

 while(n--)

 {

  scanf("%s", str+1);

  int len = strlen(str+1);

  for(i = 1; i <=
len; ++i)

   dp[i] =
INF;

  dp[0] = 0;

  for(i = 1; i <=
len; ++i)

  {

   for(j = 1; j
<= i; ++j)

   {

    if(
judge(j, i) )

     dp[i]
= min(dp[i], dp[j-1]+1);

   }

  }

  printf("%d\n",
dp[len]);

 }

 return 0;

}

 

O(n^2)

#include <cstdio>

#include <iostream>

#include <cstring>

using namespace std;

#define MAX 1005

const int INF = (1<<29);

char str[MAX];

int dp[MAX];

bool flag[MAX][MAX]; //flag[i][j]: 长度为i, 从str[j]开始有一段回文串

inline int min(int a, int b)

{

 return a < b ? a : b;

}

void init(int len)

{

 memset(flag, false, sizeof(flag));

 int i, j;

 for(i = 1; i <= len; ++i)
flag[1][i] = true;

 if(len == 1) return ;

 for(i = 1; i <= len-1;
++i)

  if(str[i] == str[i+1])

   flag[2][i]
=  true;

 for(i = 3; i <= len; ++i)

 {

  for(j = 1; j <=
len-i+1; ++j)

  {

   if(flag[i-2][j+1]
&& str[j] == str[j+i-1])

    flag[i][j]
= true;

  }

 }

}

int main()

{

// freopen("input.txt", "r", stdin);

 int caseNum, i, j;

 scanf("%d", &caseNum);

 while(caseNum--)

 {

  scanf("%s", str+1);

  int len = strlen(str+1);

  init(len);

  for(i = 1; i
<= len; ++i) dp[i] = INF;

  dp[0] = 0;

  for(i = 1; i <=
len; ++i)

  {

   for(j = 1; j
<= i; ++j)

   {

    if(
flag[j][i-j+1] )

     dp[i]
= min(dp[i], dp[i-j]+1);

   }

  }

  printf("%d\n", dp[len]);

 }

 return 0;

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