zoukankan      html  css  js  c++  java
  • 洛谷P1528 切蛋糕

    题目

    二分+随机化贪心

    首先我们有每次优先选择口小的人吃蛋糕的贪心策略。然后因为嘴巴的多少和填满嘴巴的困难程度存在单调关系,因此可以二分嘴巴的多少。而这个嘴巴个数为(mid)的时候,意味着我们需要满足前mid小的嘴巴都能被填满。判断能否填满时,可以用随机化贪心check。

    此时贪心策略发生了变化。优先让大口吃蛋糕且对于每个人,只要见到比他嘴巴大的蛋糕就可以吃。

    考虑反证,如果先让小口吃的话,很有可能所有小口都吃一个大蛋糕,从而使大口吃不到蛋糕

    #include <bits/stdc++.h>
    using namespace std;
    int n, m, ans;
    int cak[1010011], per[1001011];
    int tem[1001011];
    bool check(int k)//check是否能使k个人吃上蛋糕 
    {
    	
    	int t = 1000;
    	while (t--)
    	{
    		for (int i = 1; i <= n; i++)
    		tem[i] = cak[i];	
    		random_shuffle(tem + 1, tem + 1 + n);//随机化打乱 	
    		int Flag = 1;
    		for (int i = k; i >= 1; i--)//前k个人。 
    		{
    			int flag = 1;
    			for (int j = 1; j <= n; j++)
    				if (tem[j] >= per[i])
    				{
    					tem[j] -= per[i];
    					flag = 0;
    					break;
    				}
    			if (flag)
    			{
    				Flag = 0;
    				break;
    			}
    		}
    		if (Flag)
    			return 1;
    	}
    	return 0;
    }
    int main()
    {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++)
    		scanf("%d", &cak[i]); 
    	scanf("%d", &m);
    	for (int i = 1; i <= m; i++)
    		scanf("%d", &per[i]);//每个人的大小。切的蛋糕必须要比 
    	sort(per + 1, per + 1 + m);
    	int l = 0, r = m;
    	while (l <= r)
    	{
    		int mid = (l + r) >> 1;
    		if ( check(mid) )
    			ans = mid, l = mid + 1;
    		else
    			r = mid - 1;
    	 }
    //先满足小口的人。
    //二分最多能满足的人。
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    杭电2095--find your present (2) (异或)
    南阳168--房间安排(区间覆盖)
    南阳954--N!(数学)
    南阳--69(数的长度)
    杭电--N!(大数)
    杭电1005--Number Sequence
    杭电1108--最小公倍数
    动态规划:最长上升子序列(二分算法 nlogn)
    动态规划:最长上升子序列之基础(经典算法 n^2)
    vector函数用法
  • 原文地址:https://www.cnblogs.com/liuwenyao/p/11765867.html
Copyright © 2011-2022 走看看