USACO算法系列四十三——theme

    题目:http://www.nocow.cn/index.php/Translate:USACO/theme

    求最大重复主题序列的长度,让我想起了求最大重复子串,最大重复子串的解法,我觉得这个博客写的很好。我们可以一起学习一下(http://www.cnblogs.com/dyh333/articles/1801714.html)

    但是这道题跟最大重复子串有些不一样的地方。

    第一,子串不允许重叠。

    第二,子串的主题重复,允许加上或者减去一个数字。也就是说不是相等的。转化成相等其实也很简单,就是做一下归一化,两个子串都分别减去第一个数字。

    因此我就没采用最大重复子串的算法。而是使用最简单的算法,但是对算法做了优化。如下的for循环条件,result表示已经求得的最长主题长度。这样就可以保证不超时了。

    for (int i=0; i <= n- result; i ++)
         for(int j = i + result; j <= n- result ; j ++)

    整体代码如下:

#include <iostream> #include <fstream> #define SIZE 5000 using namespace std; ifstream fin("theme.in"); ofstream fout("theme.out"); int n; int music[SIZE] = {0}; int result = 5; bool flag = false; int cmplen(int start, int end) { int cnt = 0; for (int i=start, j= end; i < end&& j<n; i++,j++) { int s1= music[i] - music[start]; int s2 = music[j] - music[end]; if (s1 == s2) { cnt ++; } else break; } return cnt; } int main() { //输入数据 fin >> n; for (int i=0; i < n; i ++) { fin >> music[i]; } //获取最长子串 for (int i=0; i <= n- result; i ++) { for(int j = i + result; j <= n- result ; j ++) { int temp = cmplen(i, j); if (result <= temp) { flag = true; result = temp; }//end if }//end for j }//end for i if (flag) { fout<< result <<endl; } else fout << 0 <<endl; return 0; }

    运行结果如下:

Executing... Test 1: TEST OK [0.011 secs, 3032 KB] Test 2: TEST OK [0.000 secs, 3032 KB] Test 3: TEST OK [0.011 secs, 3032 KB] Test 4: TEST OK [0.000 secs, 3032 KB] Test 5: TEST OK [0.011 secs, 3032 KB] Test 6: TEST OK [0.000 secs, 3032 KB] Test 7: TEST OK [0.011 secs, 3032 KB] Test 8: TEST OK [0.011 secs, 3032 KB] Test 9: TEST OK [0.011 secs, 3032 KB] Test 10: TEST OK [0.011 secs, 3032 KB] Test 11: TEST OK [0.173 secs, 3032 KB] Test 12: TEST OK [0.162 secs, 3032 KB] Test 13: TEST OK [0.032 secs, 3032 KB] Test 14: TEST OK [0.302 secs, 3032 KB] Test 15: TEST OK [0.000 secs, 3032 KB] All tests OK.

    顺利通过了。

 

你可能感兴趣的:(USACO算法系列四十三——theme)