您的位置:首页 > 其它

[USACO] Broken Necklace

2011-02-23 15:01 204 查看
充满杯具的一道题,提交了5次才AC。。。

最简单的方法是步长为1的遍历整个项链,在断开处向两个方向搜索,然后求和的最大值(分析的解法一),但是效率不高。

如果我们找局部最长的满足要求的子串,则子串内部不再需要遍历,比如“rrrbb”,两个r之间是不需要隔断的,这样步长变大了,不过遇到brbrbr这样的情况也无能为力。。。

根据例子的提示,把字符串首尾相连构造一个2倍长的数组,就不需要考虑取模的问题了。

最外层循环i<n-1是因为i=n-1是表示在最末端断开,所以无须再进入循环了。

/*
ID:
LANG: C
TASK: beads
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 350
int main() {
FILE *fin = fopen("beads.in", "r");
FILE *fout = fopen("beads.out", "w");
char nklace[2 * N + 1];
int left, right, max;
int i, j, n;
char rc;
fscanf(fin, "%d %s", &n, nklace);
for(i = 0; i < n; i++)
nklace[n + i] = nklace[i];
i = -1;
j = 0;
right = max = 0;
while(i < n - 1) {/*i指示断开处左边的末端,i<n造成一次wa,17个w那个用例*/
left = right;
while(i - left > 0 && nklace[i - left] == 'w')/*向左搜索w,例子中最后7位bw|rwrrb出错*/
left++;
rc = 'x';
while(j < n || (j - n < i - left)) {/*原来写成j<2n,结果3个r的用例wa,没想到j>n时会与前面的划分重叠这一条件*/
if(rc == 'x' && nklace[j] != 'w')
rc = nklace[j];
else if(rc != 'x' && nklace[j] != 'w' && rc != nklace[j])
break;
j++;
}
right = j - i - 1;
if(left + right > max)
max = left + right;
i = j - 1;
}
fprintf(fout, "%d/n", max);/*写成了printf,杯具了一次!*/
exit(0);
}


分析的解法一:定义break的位置和方向,从1到n进行遍历,找最大值。但是注意类似“rrr”这种情况会导致两个方向重复计算,要特殊处理。

分析的解法二:DP,唉!没想到啊,O(n)的复杂度。解法声明了两个800*2,一个800,一个400(这个可以省下的)的字符数组,明显的空间换时间。

分析的解法三:与解法一类似,但是是单向遍历找到每个开始字符可以构造的最长的序列,此序列是断开处两个字符串的整体,比如“rrrbbrr”,第一次遍历起始点为r,得到长度为5,断点在rrr和bb之间。

整体来说,此题没有想到DP很是失败,我的方法不好理解,想的条件还多,易错,调试麻烦,没有解法一的易懂以及解法二的简洁,解法三比较有新意。在分析题的过程中有些浮躁和草率,没有集中精神,比如右边子串与左边子串的重叠问题,当右边子串变成左边吸收原来的左边子串邻接的w问题等等,这导致在最后编码时很多边界条件和特殊情况没有考虑到,wa多次!

心平气和,再接再厉!!

最后一点:把心里想的用文字写出来真是一件不太容易的事情。。。:P
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: