一道打着洛谷黑题招牌的简单贪心
题目
题目描述
有两个人S和M,他们每人有一段长度为N的数字,两个人在每一轮游戏中都可以按顺序拿出一个数字,谁的数字小谁就接受一次惩罚。若相等两者都没有惩罚。另外,M珂以重新安排自己数字的顺序,问 M的最少被惩罚次数 和 S的最多被惩罚次数 是多少。
输入输出格式
输入格式
输入的第一行包含一个整数n (1<=n<=1000)——S和M将要使用的纸牌中的数字。
第二行包含n个没有空格数字——S的数字。
第三行包含n个没有空格数字——M的数字。
输出格式
第一行先把M最少受罚次数输出。
第二行输出S最多的受罚次数。
输入输出样例
题目思路
有点类似于田忌赛马的问题, 可以想到用贪心的最优策略
第一问
求S最小受罚次数
M可以按任意顺序拿出数字,枚举遍历S中的每一个数,对于每一个数 a 只有两种情况:
1
W中有还未用且 ≥ a 的数,此时选满足条件的最小的数
2
W中的数都 < a 的数, 此时选未用的数中最小的数
代码
for (int i = 1; i <= len; i++) {
bool ok = 0;
for (int j = 1; j <= len; j++)
if (a[j] >= b[i] and !used[j]) {ok = 1, used[j] = 1; break;}
if (!ok)
for (int j = 1; j <= len; j++)
if (!used[j]) {used[j] = 1, ans1++; break;}
}
第二问
求M最大受罚数
做法相似,枚举遍历S中的每一个数,对于每一个数 a 只有两种情况:
1
W中有还未用且 > a 的数,此时选满足条件的最小的数
2
W中的数都 ≤ a 的数, 此时选未用的数中最小的数
代码
for (int i = 1; i <= len; i++) {
bool ok = 0;
for (int j = 1; j <= len; j++)
if (a[j] > b[i] and !used[j]) {ok = 1, used[j] = 1, ans2++; break;}
if (!ok)
for (int j = 1; j <= len; j++)
if (!used[j]) {used[j] = 1; break;}
}
完整代码
#include <bits/stdc++.h>
using namespace std;
char a[1005], b[1005];
bool used[1005]; //used记录是否被用
int len, ans1, ans2; //ans1记录 M 最少受罚次数, ans2记录 S 最多受罚次数
int main() {
scanf ("%d %s %s", &len, b + 1, a + 1);
sort (a + 1, a + len + 1);
//第一问:
for (int i = 1; i <= len; i++) {
bool ok = 0; //ok记录是否有满足要求的数
for (int j = 1; j <= len; j++)
if (a[j] >= b[i] and !used[j]) {ok = 1, used[j] = 1; break;}
//如果没有则选最小的数
if (!ok)
for (int j = 1; j <= len; j++)
if (!used[j]) {used[j] = 1, ans1++; break;} //此时受罚次数 +1;
}
memset (used, 0, sizeof (used)); //清零used数组
//第二问:
for (int i = 1; i <= len; i++) {
bool ok = 0; //ok记录是否有满足要求的数
for (int j = 1; j <= len; j++)
if (a[j] > b[i] and !used[j]) {ok = 1, used[j] = 1, ans2++; break;}
//如果没有则选最小的数
if (!ok)
for (int j = 1; j <= len; j++)
if (!used[j]) {used[j] = 1; break;} //此时不受罚次数 +1;
}
printf ("%d\n%d", ans1, ans2);
return 0;
}