MaximumPalindromeScore (有道难题复赛400)

比赛时候没做出来,现在无法系统测试,算法看起来似乎是没问题的。

简要思想就是一层层生成所有子串,然后计算这些子串转换成同一字符串所需要的最小转换次数。
用函数min_to_make_equal来生成:将一个vector<string>中的所有字符串转换成同一个字符串,所需要改变的最小字符数。对于last数组中的每一个字符串,将这个字符串分两半,后半部翻转。计算这些字符串转换成同一个字符串所需要的最小改变次数,如果这个次数小于等于m,说明我们可以在m次将它变成回文。计数加1。
注意如果字符串长度为奇数,我们还要先计算一下将每个中间字符变成统一字符所需要的转换次数,用m减去它。

#include <iostream>
#include 
<sstream>
#include 
<vector>
#include 
<string>
#include 
<algorithm>

using namespace std;

int cnt[51][26];

   
class MaximumPalindromeScore
              { 
              
public
              
int maximize(string word, int m) 
                  {

                  vector
<string>last;
                  last.push_back(word);
                  
                  
int res = 0;

                  
int i;

                  
while(true){

                      
//如果是串的长度为奇数,m减去"将中间字符变成统一字符需要的转换次数"
                      if(last[0].size()%2==1){
                          vector
<string> mid;
                          
for(i=0;i<last.size();++i){
                            mid.push_back(
string(1,last[i][last[i].size()/2]));
                          }
                          m
-=min_to_make_equal(mid);
                      }
                      
                      vector
<string> tmp;

                      
//将每个字符串分割成两个子串,前半部不变,后半部翻转
                      
//如果在这一层次上仍满足回文性质,则这些字符串应该能够转换成相同的字符串
                      for(i=0;i<last.size();++i){
                          
int n = last[i].size();
                        
string s1 = last[i].substr(0,n/2);
                        
string s2 = last[i].substr(n-n/2,n/2);
                        reverse(s2.begin(),s2.end());
                        tmp.push_back(s1);
                        tmp.push_back(s2);
                      }

                      
if(min_to_make_equal(tmp)<=m)
                          res
++;
                      
else 
                           
break;

                      
//长度为奇数,不需要再计算下去了。
                      if(last[0].size()%2==1break;

                      last 
= tmp;                  
                        
                        }
                    
return res;
                  }


              

              
int min_to_make_equal(vector<string> &vs){
                   memset(cnt,
0,sizeof(cnt));

                   
int i,j;

                   
for(i=0;i<vs[0].size();++i)
                       
for(j=0;j<vs.size();++j)
                           cnt[i][vs[j][i]
-'a']++;

                   vector
<char> equal;

                   
for(i=0;i<vs[0].size();++i){
                       
int max = 0;
                       
for(j=0;j<26;++j){
                           
if(cnt[i][j]>cnt[i][max])
                               max 
= j;
                       }
                       equal.push_back(
'a'+max);
                   }

                   
int res = 0;

                   
for(i=0;i<vs.size();++i){
                       
for(j=0;j<vs[i].size();++j){
                        
if(vs[i][j]!=equal[j])
                            res
++;
                       }
                   }

                   
return res;
              }
};
附原题:
“回文分数”游戏并不简单。游戏的目标是修改最多maxChanges个字符使得一个字符串word的回文分数最高。只允许修改,不许增加或者删除字
符。一个字符串的回文分数定义如下:
如果字符串不是回文串,则分数为0。
如果字符串是回文串,且长度为奇数,则分数为1。
如果字符串是回文串,且长度为偶数,我们将它分为左右两半。计算它的一半子串的回文分数为K(两个一半子串得分一定相同),则原字符串的回文分数为K
+ 1。
给定一个字符串word和一个型整数maxChanges,返回最多修改maxChanges个字符后最大可能的回文分数。

DEFINITION
Class:MaximumPalindromeScore
Method:maximize
Parameters:String, int
Returns:int
Method signature:int maximize(String word, int maxChanges)


NOTES
-回文串的定义是一个字符串从前向后读和从后向前读完全一样。


CONSTRAINTS
-word包含1到50个字符(含1和50)。
-word 只包含小写字母 ('a'-'z')。
-maxChanges 取值范围是0到50(含0和50)。


EXAMPLES

0)
"coder"
2

Returns: 1

我们可以把c改成r,把e改成o,得到"rodor"。这是一个奇数长度的回文串,所以得分为1。

1)
"abcbxabcba"
1

Returns: 2

如果把x改成a,得到偶数长度的回文串"abcbaabcba"。它的一半子串是奇数长度的回文串"abcba",所以子串分数为K = 1,因而最后
得分是K + 1 = 2。

2)
"abcdefghijklmnop"
15

Returns: 5

可以把这个字符串修改成"aaaaaaaaaaaaaaaa"、"eeeeeeeeeeeeeeee"或其他14种串,回文得分均为5。

3)
"ssssssssssssssss"
15

Returns: 5

有时不做所有允许的改变可能更好。

4)
"vyyvvzzvvxxvvxxv"
4

Returns: 3



5)
"a"
0

Returns: 1

posted on 2009-06-22 20:42 YZY 阅读(1313) 评论(4)  编辑 收藏 引用 所属分类: AlgorithmTopCoder

评论

# re: MaximumPalindromeScore (有道难题复赛400) 2009-06-24 00:33 goodidea

第二题考虑的确实不错,学习了,我QQ601880671,你加我吧,以后可以方便交流。。。
邮箱gc063tzf@163.com  回复  更多评论   

# re: MaximumPalindromeScore (有道难题复赛400) 2009-06-24 08:39 YZY

@goodidea
呵呵,我很少上QQ.还是邮件交流比较方便些:-)  回复  更多评论   

# re: MaximumPalindromeScore (有道难题复赛400) 2009-06-24 22:02 xiao7cn

我这个算法是不是更简洁呢?

import java.util.*;

public class MaximumPalindromeScore {

public int maximize(String word, int maxChanges) {
int L = word.length();
int score = 1;
while (L % 2 == 0) {
L /= 2;
score++;
}
int change = Integer.MAX_VALUE;
score++;
int[] stat = new int[26];

while (change > maxChanges && L <= word.length()) {
score--;
change = 0;
int p = 0, q = L - 1;
while (p <= q) {
Arrays.fill(stat, 0);
for (int j = 0; j < word.length() - q; j += L) {
stat[word.charAt(p + j) - 'a']++;
stat[word.charAt(q + j) - 'a']++;
}
int max_char = 0;
for (int ii = 0; ii < stat.length; ii++)
if (stat[max_char] < stat[ii])
max_char = ii;
if (p != q)
change += word.length() * 2 / L - stat[max_char];
else
change += word.length() / L - stat[max_char] / 2;

p++;
q--;
}
L *= 2;
}

return change > maxChanges ? score - 1 : score;
}

}
  回复  更多评论   

# re: MaximumPalindromeScore (有道难题复赛400) 2009-06-24 22:19 止于自娱

@xiao7cn
是的:-)  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

<2009年6月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

统计

常用链接

留言簿(2)

随笔分类

随笔档案

搜索

积分与排名

最新评论

阅读排行榜