把数字当成字符串,按 x+y 与 y+x 的大小决定拼接顺序,排序后连接得到最大数。
OJ: luogu
题目 ID: P1012
难度:普及-
标签:字符串排序贪心python
日期: 2026-07-06 20:42
题意
给出 n 个正整数,可以任意调整顺序并首尾拼接,要求组成最大的整数。
思路
先看一个小数据暴力:
cpp
// brute.cpp:小数据暴力解,使用选择序列递归枚举所有拼接顺序。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10;
int n;
string a[MAXN];
bool used[MAXN];
int choose_order[MAXN]; // choose_order[i] 表示第 i 个位置放哪个原数
string best_answer;
string calc_answer() {
string res = "";
for (int i = 1; i <= n; i++) {
res += a[choose_order[i]];
}
return res;
}
void update_answer() {
string current = calc_answer();
if ((int)current.size() > (int)best_answer.size() ||
((int)current.size() == (int)best_answer.size() && current > best_answer)) {
best_answer = current;
}
}
void dfs_order(int dep) {
if (dep == n + 1) {
update_answer();
return;
}
// 这一层只记录第 dep 个拼接位置选择哪个数。
for (int i = 1; i <= n; i++) {
if (!used[i]) {
used[i] = true;
choose_order[dep] = i;
dfs_order(dep + 1);
used[i] = false;
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
best_answer = "";
dfs_order(1);
cout << best_answer << '\n';
return 0;
}暴力枚举所有排列,再拼接比较,复杂度是 n!。
正解只需要解决两个字符串 x 和 y 的相对顺序:
- 如果
x在前,局部结果是x+y; - 如果
y在前,局部结果是y+x。
为了让整体最大,若 x+y > y+x,就应该让 x 排在 y 前面。按照这个比较规则排序后,把所有字符串连接起来就是答案。
例如 13 和 312:
text
13 + 312 = 13312
312 + 13 = 31213所以 312 应该排在 13 前面。
Python 知识
- 输入数字不要转成整数排序,而要保留为字符串。
- Python 排序默认使用
key,遇到这种“两两比较”规则时,可以用functools.cmp_to_key。 - 比较函数返回负数表示第一个参数排在前面。
代码
python
from functools import cmp_to_key
import sys
def compare(x, y):
if x + y > y + x:
return -1
if x + y < y + x:
return 1
return 0
def main():
tokens = sys.stdin.read().split()
n = int(tokens[0])
numbers = tokens[1:1 + n]
numbers.sort(key=cmp_to_key(compare))
print("".join(numbers))
if __name__ == "__main__":
main()复杂度
排序比较次数为 L,每次比较会拼接并比较两个长度约 2L 的字符串,总复杂度约为
空间复杂度是
总结
拼数不能按数值大小排序。真正的局部标准是比较 x+y 和 y+x,谁能让拼接结果更大,谁就排在前面。