寻找大富翁

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
bool comp(int a,int b)//从大到小
{
    return a>b;
}
int num[100010];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m),n+m)
    {
        memset(num,0,sizeof(num));
        for(int i=0;i<n;++i)
        {
            scanf("%d",&num[i]);
        }
        m=min(n,m);
        //sort(num,num+n,greater<int>());从大到小排序
        sort(num,num+n,comp);
        for(int i=0;i<m-1;++i)
        {
            printf("%d ",num[i]);
        }
        printf("%d\n",num[m-1]);
    }
    return 0;
}
<think>好的,我需要解决用户关于PTA平台“寻找大富翁”问题的Java实现或解题思路。首先,我得理解题目要求。题目要求从N个人找出资产M位的富翁,其中N可能很大(到10^6),而M最多是10。这种情况下,效率很重要。 根据提供的引用,特别是引用[4]和[5],提到当M较小的时候,可以采用维护一个大小为M的最小堆,或者先填满M个元素,之后每个新元素如果比堆顶大就替换,然后调整。这样可以保证时间复杂度是O(N log M),比完全排序的O(N log N)更高效,特别是当M远小于N时。 不过用户提到的是Java实现,所以需要考虑Java中的数据结构。Java的PriorityQueue默认是最小堆,但可以通过比较器改为最大堆。但在这个问题中,可能需要维护一个最小堆,以便快速替换最小的元素。例如,保持堆的大小为M,当新元素比堆顶大时,替换堆顶并调整堆。 另外,引用[3]和[5]指出输入可能很大,N到10^6,所以在读取输入时要注意效率,不能用Scanner,而应该用BufferedReader来加快读取速度。特别是处理大量数据时,输入输出效率很关键。 解题步骤大致如下: 1. 读取N和M。 2. 处理特殊情况,比如当M为0或者N为0的情况。 3. 如果N <= M,直接排序输出即可。 4. 否则,使用一个最小堆,初始填充M个元素。 5. 遍历剩余的元素,每个元素与堆顶比较,如果更大就替换堆顶,并调整堆。 6. 最后将堆中的元素排序(降序)输出。 在Java中,可以用PriorityQueue实现最小堆。不过要注意,默认的PriorityQueue是最小堆,所以比较器需要正确设置。或者,可以自定义比较器让小的元素在堆顶,这样每次替换的时候,堆顶是最小的,方便比较。 另外,处理输入的时候需要注意,由于输入可能有多个空格分隔,需要用split方法分割,并且处理可能的多个空格。或者使用流式处理,逐个读取数字。 还有,题目中提到输出是M个富翁的资产,按非递增顺序排列。所以最后需要将堆中的元素取出并逆序排序。 需要注意的是,当N小于M时,应该输出所有N个元素的降序排列,而不是补零或者其他处理。 可能的问题点包括输入处理效率、堆的正确维护,以及最后的排序步骤。此外,Java的PriorityQueue的默认行为是否符合需求,是否需要自定义比较器。 例如,创建PriorityQueue时,使用自然顺序的话是最小堆,堆顶是最小元素。这正是需要的,因为当新元素比堆顶大时,替换掉堆顶,然后重新调整堆,保持堆的大小为M。这样遍历完所有元素后,堆中保存的就是最大的M个元素。 最后,将堆中的元素取出,由于是最小堆,需要逆序排序后输出。可以用一个数组来保存结果,然后反转数组,或者使用Collections.reverse方法。 现在需要考虑代码的结构: - 读取输入,使用BufferedReader。 - 处理输入中的N和M,注意可能的错误情况。 - 读取资产数组,可能很大,所以用长整型。 - 根据N和M的大小选择处理方式。 - 使用优先队列维护M大的元素。 - 最后处理输出。 例如,代码的大致结构可能是: import java.io.*; import java.util.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] firstLine = br.readLine().split(" "); int N = Integer.parseInt(firstLine[0]); int M = Integer.parseInt(firstLine[1]); if (M <= 0 || N <= 0) { System.out.println(); return; } long[] assets = new long[N]; String[] parts = br.readLine().split("\\s+"); for (int i = 0; i < N; i++) { assets[i] = Long.parseLong(parts[i]); } // 处理逻辑 if (M > N) M = N; PriorityQueue<Long> minHeap = new PriorityQueue<>(); for (int i = 0; i < M; i++) { minHeap.offer(assets[i]); } for (int i = M; i < N; i++) { if (assets[i] > minHeap.peek()) { minHeap.poll(); minHeap.offer(assets[i]); } } List<Long> result = new ArrayList<>(minHeap); Collections.sort(result, Collections.reverseOrder()); // 输出 StringBuilder sb = new StringBuilder(); for (int i = 0; i < result.size(); i++) { sb.append(result.get(i)); if (i != result.size() - 1) { sb.append(" "); } } System.out.println(sb.toString()); } } 但需要注意,当N <= M时的情况,此时应该对整个数组排序,取降序的N个元素。例如: 如果N <= M,则直接对数组进行降序排序,输出N个。 例如: if (N <= M) { M = N; Arrays.sort(assets); // 然后逆序 // 转换为列表然后反转 List<Long> list = new ArrayList<>(); for (long num : assets) { list.add(num); } Collections.sort(list, Collections.reverseOrder()); // 然后输出 } else { // 使用堆处理 } 或者更高效的是,直接排序数组然后取M个元素逆序。 不过对于N非常大的情况,比如1e6,Arrays.sort可能会使用快速排序,时间复杂度是O(N log N),而如果M很小的话,堆方法更高效。但根据题目中的条件,当N <= M时,直接全排序即可。而题目中的M<=10,所以在一般情况下,当N > M时,用堆方法更高效。 另外,在输入处理中,split("\\s+")可以处理多个空格的情况,这样分割后的数组不会有空字符串。 但需要注意,当输入行可能非常长时(例如1e6个数字),split方法可能效率不高,或者导致内存问题。此时,可以考虑使用StreamTokenizer或者逐个读取的方式。但Java中处理这种情况可能比较麻烦,而题目中的输入可能允许用split,因为PTA的测试用例可能不会让行超过内存限制。不过对于N=1e6,用split会导致生成一个长度为1e6的字符串数组,这在Java中可能会占用较多内存,但通常PTA的题目会考虑到这一点,允许通过。 综上,正确的Java实现应该采用优先队列维护M个最大的元素,最后进行逆序输出。同时处理输入输出的效率问题。</think>### PTA 寻找大富翁 Java 实现思路 #### 核心思路 1. **输入处理**:使用 `BufferedReader` 高效读取大规模数据,注意处理空格分隔的资产值。 2. **堆维护**:利用最小堆(`PriorityQueue`)动态维护 $M$ 大元素: - 堆大小固定为 $M$,新元素若大于堆顶则替换并调整堆。 3. **时间复杂度优化**:时间复杂度为 $O(N \log M)$,优于完全排序的 $O(N \log N)$[^4]。 #### 代码实现 ```java import java.io.*; import java.util.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] firstLine = br.readLine().split(" "); int N = Integer.parseInt(firstLine[0]); int M = Integer.parseInt(firstLine[1]); if (M <= 0 || N <= 0) { System.out.println(); return; } long[] assets = Arrays.stream(br.readLine().split("\\s+")) .mapToLong(Long::parseLong) .toArray(); M = Math.min(M, N); // 修正M值 if (N <= M) { Arrays.sort(assets); reverseArray(assets); printResult(assets, M); return; } // 最小堆维护M大元素 PriorityQueue<Long> minHeap = new PriorityQueue<>(); for (int i = 0; i < M; i++) { minHeap.offer(assets[i]); } for (int i = M; i < N; i++) { if (assets[i] > minHeap.peek()) { minHeap.poll(); minHeap.offer(assets[i]); } } // 转换为数组并降序输出 Long[] result = minHeap.toArray(new Long[0]); Arrays.sort(result, Collections.reverseOrder()); printResult(result, M); } private static void reverseArray(long[] arr) { int left = 0, right = arr.length - 1; while (left < right) { long temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; left++; right--; } } private static void printResult(Long[] arr, int M) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < M; i++) { sb.append(arr[i]); if (i != M - 1) sb.append(" "); } System.out.println(sb); } private static void printResult(long[] arr, int M) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < M; i++) { sb.append(arr[i]); if (i != M - 1) sb.append(" "); } System.out.println(sb); } } ``` #### 关键步骤说明 1. **输入修正**:若 $M > N$,修正 $M = N$ 避免越界。 2. **堆操作**:通过最小堆筛选出最大的 $M$ 个元素,堆顶始终为当最小值。 3. **结果输出**:对堆中元素降序排序后输出,满足题目要求的非递增顺序[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值