Best Cow Line(POJ 3617)

题目翻译:
给定一个长度为 n 的字符串 a ,有一个空串 T ,现在你需要选择 n 次:
将 a 的头部字符删除,加到 T 的尾部。
将 a 的尾部字符删除,加到 T 的尾部。
目标得到字典序最小的 T
数据限制:n ≤ 2000。
输出要求:每80个一行。
样例输入输出:
输入:     输出:
6              ABCDCB
A
C
D
B
C
B
思路点拨:
这道题是一道经典的贪心问题,得先弄清楚贪心策略:
 
要让一个串字典序尽量小,优先让它的第一个字母尽量小,然后再考虑让它的第二个字母尽量
小,再考虑第三个......
 
于是我们得到了一个自然的贪心算法——每次将 a 的头尾中较小的字符放到 的末尾。
例如:a = abdc
我们先比较 a 的头尾,发现 ‘ a ’ 比较小,就把它放到  的末尾
重复此步骤,我们就会得到最小的  T :abcd
 
但是上述算法有一个缺陷:当 a 的头尾字母相同时,没有定义该选择哪一个。
这时我们就得进行判断:
当 a 的头尾字母相同时,考虑从头尾取的第二个字符,优先选择较小的。
当 a 的头尾前两个字符都相同时,考虑从头尾取的第三个字符,优先选择较小的。
......
 
例如:a = cbac
我们发现 a 的头和为都相同,那我们就得比较他们前面的一位:
发现 ‘ a ’ 比较小,因此我们选尾巴上的 ‘ c ’ ,把它放到  的末尾
重复此步骤,我们就会得到最小的  T :cabc
 
这样,我们就得到了一个正确的贪心算法,代码也迎刃而解了。
 
参考代码:
#include<iostream>
using namespace std;
int main()
{
	int n;
    char a[2001]; 
    cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];//输入 
	char ans[2001];//定义一个答案数组 
	int l=1,r=n,num=0;//定义l和r用来记录现在要比较哪两个位置
                      //num表示目前ans到第几位了	 
	while(num<=n)//一旦num=n,说明全部取完 
	{
		//如果头小于尾,去头 
		if(a[l]<a[r]) ans[++num]=a[l++];
		//如果两者相等,比较前面 
		else if(a[l]==a[r])
		{
			int posl=l+1,posr=r-1;//定义两个指针 
			while(a[posl]==a[posr]&&posl<posr) 
			posl++,posr--;//判断到什么时候两者不一样了
			              //可以进行比较了                                    
			ans[++num]=a[posl]<a[posr]?a[l++]:a[r--];//三目运算,取值 
		}
		//如果头大于尾,去尾 
		else ans[++num]=a[r--];
	}
	for(int i=1;i<=n;i++) 
	{
	cout<<ans[i];
	if(i%80==0) cout<<endl;//格式要求 
	}
	return 0;
}

有什么看不懂的,可以私信我。

本人还是一名小学生,希望多多关照!

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱编程的小芒果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值