POJ 3617 Best Cow Line(贪心)

来源:互联网 发布:数据分析属经济学吗 编辑:程序博客网 时间:2024/06/15 13:17

题目链接:http://poj.org/problem?id=3617

刷挑战的贪心部分的路上,发现自己学了一年啥也不会。。。贪心的单调性和大致证明我都做不到。。。

来说这道题,这道题,贪心是显然的,如果头和尾的字母不一样,那么肯定是选择字母较小的那个放入答案中。但是,难点在于,如果他们是一样的呢?我想了几种解决方案。

1,直接取头(or尾)的那个,但是这样显然是错误的,样例都跑不过去。

2,既然他们第一个相同,我们就比较他们的第二个,如果第二个相同,比较第三个。直到第N个不相同,较小的那方直接全部插入答案中。但是这样也是错误的。。。例如ACDECA,这样做的话我就直接把ACD插入到答案里面,但最优的结果明显是AACCDE。所以这种贪心也是不正确的。

3,结合第二个分析,那我选择AA相同的时候,比较下一层,如果下一层相同,如CC,我们判断A C的大小,A < C,所以直接把AA取掉。如果不相同,如CC和DE,我们选择最小的,D,判断和C的关系,C < D,所以我们把外层两个C先拿掉,否则先拿掉内层的……这里开始已经十分十分混乱了,感觉脑袋不够用,这要分支成许多许多情况。(这里我是真的太贪了,想一次性拿两个, 把问题复杂化。还是应该回到每次只想着拿一个,哪个最优的基础上来。)

4,正解,简洁的做法。直接从头到尾建立一个字符串S1,从尾到头建立一个字符串S2,如果S1 < S2,那么就取掉头部的字母,否则取掉尾部的字母。为什么这样的正确的呢?这就是一种贪心,当头和尾相同的时候,我们选择当前最优解,就是如果从头部建立的字符串字典序小于尾部,那么当前说明选择头部为最优解,否则选择尾部为最优解。就像ACDECA一样,我们建立S1 = ACDECA, S2 = ACEDCA,S1 < S2,所以取掉头部的A是最优的。

代码如下:(想改自己代码风格真是麻烦,不伦不类)

#include<iostream>#include<cstring>#include<cstdio>using namespace std;int main(){char str[2005], ch, ans[2005], str_1[2005], str_2[2005];int n;scanf("%d", &n);for(int i = 0; i < n; i++){ch = getchar();while(ch < 'A' || ch > 'Z')ch = getchar();str[i] = ch;}int head = 0, end = n - 1;int p = 0;while(head <= end){if(str[head] != str[end]){if(str[head] < str[end]){ans[p++] = str[head];head++;}else{ans[p++] = str[end];end--;}}else{int p1 = 0, p2 = 0;for(int i = head; i <= end; i++)str_1[p1++] = str[i];str_1[p1++] = '\0';for(int i = end; i >= head; i--)str_2[p2++] = str[i];str_2[p2++] = '\0';if(strcmp(str_2, str_1) > 0){ans[p++] = str[head];head++;}else{ans[p++] = str[end];end--;}}}ans[p++] = '\0';for(int i = 0; i < p - 1; i++){if(i && i % 80 == 0)cout << endl;cout << ans[i];}cout << endl;return 0;} 

这样写还是太糟糕了,花费了许多时间,看到正解的写法感觉还是妙的多。

#include<iostream>#include<cstring>#include<cstdio>using namespace std;int main(){char str[2005], ch;int n;bool flag;scanf("%d", &n);for(int i = 0; i < n; i++){ch = getchar();while(ch < 'A' || ch > 'Z')ch = getchar();str[i] = ch;}int head = 0, end = n - 1, cnt = 0;while(head <= end){if(cnt && cnt % 80 == 0)putchar('\n');flag = false;for(int i = 0; head + i <= end; i++){if(str[head + i] < str[end - i]){flag = 1;break;}else if(str[head + i] > str[end - i]){break;}}if(flag)putchar(str[head++]);elseputchar(str[end--]);cnt++;}putchar('\n');return 0;} 


原创粉丝点击