首页 > 试题广场 >

叠大饼

[编程题]叠大饼
  • 热度指数:258 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
个大饼,每一个大饼都有一个半径如果,那么可以把第个大饼放在第个大饼上面,你可以将大饼叠在一起,如。请问最少可以将这些大饼叠几堆。

输入描述:
第一行一个整数
接下来个整数


输出描述:
输出一行,一个整数表示最少堆数。
示例1

输入

4
4 2 4 3

输出

2

说明

一个半径为4的大饼一堆,另外一个半径为2,3,4的大饼叠在一堆
示例2

输入

7
4 9 7 7 3 3 2

输出

2

说明

一种情况为:9,7,4,3,2 一堆,7,3一堆
示例3

输入

9
2 10 3 9 2 5 3 2 9

输出

3
找同一数字出现最多的次数就可以
#include <bits/stdc++.h>
using namespace std;
int main(){
    int n,x;
    map<int,int>mp;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>x;mp[x]++;
    }
    int maxx=0;
    for(auto [x,y]:mp){
        maxx=max(maxx,y);
    }
    cout<<maxx<<'\n';
}


发表于 2022-01-12 16:17:46 回复(0)
贪心:找出出现次数最多的半径的出现次数即可
#include <iostream>
#include <unordered_map>
using namespace std;

int main()
{
    int n;
    cin >> n;
    unordered_map<int, int> data;
    int res{0};
    while (n--)
    {
        int temp;
        cin >> temp;
        ++data[temp];
        res = max(res, data[temp]);
    }
    cout << res;
    return 0;
}


发表于 2022-04-02 23:12:00 回复(0)
依题意,每堆大饼的半径一定是互不相同的。其实就是一个数组,最多可以分成几个元素各不相同的子数组。我们可以先将所有的半径相同的大饼放入到一个队列中去,假设有n个队列,每个队列出队一次,这些队首就能构成一堆大饼。不断出队,直到所有的队列都空掉,这时候形成的堆数一定是最少的。
为了算法的性能,可以统计每个大饼半径的频数,然后通过自减频数来模拟出队行为。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        String[] strs = br.readLine().split(" ");
        HashMap<Integer, Integer> counter = new HashMap<>();
        for(int i = 0; i < n; i++){
            int cake = Integer.parseInt(strs[i]);
            counter.put(cake, counter.getOrDefault(cake, 0) + 1);
        }
        int count = 0;
        while(!counter.isEmpty()){
            List<Integer> keys = new ArrayList<>(counter.keySet());
            for(int key: keys){
                if(counter.get(key) == 1){
                    counter.remove(key);
                }else{
                    counter.put(key, counter.get(key) - 1);
                }
            }
            count++;
        }
        System.out.println(count);
    }
}

发表于 2021-12-29 14:38:00 回复(0)
先创建一个array并把数据存入其中,并按照半径大小进行排序。
饼从大往小叠。同样大小的饼不可以叠加,则最少需要 半径最大饼 的出现次数 堆。

例:4个饼,1,2,4,4。 最大为4, 和4 不可重叠,4出现2次,则最少需要2堆。

从大到小依次堆叠,若 当前饼数量 小于等于 半径比它大的所有饼里最多的数,
那么 当前饼 总有地方放,不需要额外成为底座。
例:5个饼,1,1,3,4,4. 
最大饼为4,第二大饼为3.。第二大饼不多于最大饼,它就能找到地方放(放在任意一个4饼上)。
依次类推,第三大饼为1,它一个放在3上一个放在4上。
只要半径比它大的饼里有任意饼数量大于等于它(半径为4饼的,数量为2),它就有地方放。
(半径比它大的都不影响它叠在最上面的权限,比如半径为3的饼,不管放在哪里,半径为1的饼都能放在它头上。)
则 当且仅当 当前饼数量超过了 半径比它大的数量最多的饼 ,
当前饼才需要成为新的底座。
例:6个饼:1,1,1,3,4,4
两个4为底座,3可放在任意一堆,
前两个1 可以分别放在这两个堆的顶端
但第三个1 不可与前两个1堆叠,它只能成为新的底座。

那么本题则可以写为:寻找出现频率最高的饼。
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
	int n;
	cin >> n;//输入n
	int* a = new int[n];//创建array a,数量为n 
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];//输入所有的数字
	}

	sort(a,a+n);//对 array a 进行从小到大的排序
	int max = 1;//历史出现频率最大的数字的 出现次数,最小为1
	int num = 1;//当前数字出现次数,最小也为1
	for (int j = 1; j < n; j++)//从第二个数字开始
	{
		if (a[j] == a[j - 1])//如果当前数字和前一个数字相同
		{
			num++;//则当前数字出现次数+1
			if (num > max)//如果当前数字出现频率超过历史最大值
			{
				max = num;//则当前数字出现的频率覆盖历史最大值
			}
		}
		else {//若当前数字和前一个不一样
			num = 1; //则重置当前数字出现次数
		}
	}
	cout << max << endl;//输出历史出现频率最高的数字的次数

}

发表于 2022-03-03 10:47:59 回复(0)