洛谷题单指南-贪心-P1106 删数问题
原题链接:https://www.luogu.com.cn/problem/P1106
题意解读:如何删数,让剩下的数最小,贪心选择问题。
解题思路:
方法1:删数法
先看样例:
175438
4
第1次遍历:删掉7,剩下15438
第2次遍历:删掉5,剩下1438
第3次遍历:删掉4,剩下138
第4次遍历:删掉8,剩下13,即为结果
所以,贪心策略如下:
1、遍历每一个数,如果前一个数比后一个数大,则删掉前一个数
2、以上过程重复k次,即删除k个数
3、特别的,如果是最后一个数,要和0比较,如果比0大则删掉最后一个数
需要注意两点:
1、如果数全部被删除,答案是0,需要特殊处理
2、删除后,可能出现前导0,输出时需要去除前导0
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 255;
string s;
int a[N], cnt, k;
int main()
{
cin >> s >> k;
for(int i = 0; i < s.size(); i++) a[i + 1] = s[i] - '0';
cnt = s.length();
while(k--) //删k次
{
for(int i = 1; i <= cnt; i++) //从头到尾遍历
{
if(a[i] > a[i + 1]) //前面数比后面的数大,则删掉前面的数,注意最后一个数要和0比较
{
for(int j = i; j <= cnt; j++) //删掉a[i]
{
a[j] = a[j+1];
}
cnt--; //数的数量减少1个
break;
}
}
}
if(cnt == 0) cout << 0; //都被删了,输出0
else
{
int i = 1;
while(!a[i] && i < cnt) i++; //去除前导0
while(i <= cnt) cout << a[i++];
}
return 0;
}
方法2:选数法
对于样例:
175438
4
第一遍遍历:从第一~第五(保证选第一个数后,后面的数数量够用),选最小的数,是1,即第一个
第二遍遍历:从1后面的数开始,即第二~第六(保证选第二个数后,后面的数数量够用),选最小的数,是3,即第六个数
选择的数为13
这里贪心策略如下:
对于n位数,要删k个,即保留r=n-k个
重复r次选数,
第一次,从头开始一直到r+1的位置,选第一个最小的数
在从上一次最小的数开始,一直到r+2的位置,选第二个最小的数
以此类推,选择r次之后,即得到答案。
同样,要注意两点:
1、如果剩下的数字数量为0,直接输出0
2、选择的数如有前导0,需要去除
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 255;
string s;
int a[N], cnt, k;
int main()
{
cin >> s >> k;
for(int i = 0; i < s.size(); i++) a[i + 1] = s[i] - '0';
cnt = s.length();
while(k--) //删k次
{
for(int i = 1; i <= cnt; i++) //从头到尾遍历
{
if(a[i] > a[i + 1]) //前面数比后面的数大,则删掉前面的数,注意最后一个数要和0比较
{
for(int j = i; j <= cnt; j++) //删掉a[i]
{
a[j] = a[j+1];
}
cnt--; //数的数量减少1个
break;
}
}
}
if(cnt == 0) cout << 0; //都被删了,输出0
else
{
int i = 1;
while(!a[i] && i < cnt) i++; //去除前导0
while(i <= cnt) cout << a[i++];
}
return 0;
}