贪心1合集

贪心1合集

青藤oj #10021. 均分纸牌

题目描述

有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。

移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号为 2 的堆上;在编号为 N 的堆上取的纸牌,只能移到编号为 N-1 的堆上;其他堆上取的纸

牌,可以移到相邻左边或右边的堆上。

现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。

例如 N=4,4 堆纸牌数分别为:① 9 ② 8 ③ 17 ④ 6  移动3次可达到目的:  从 ③ 取 4 张牌放到 ④ (9 8 13 10) -> 从 ③ 取 3

张牌放到 ②(9 11 10 10)-> 从 ② 取 1 张牌放到①(10 10 10 10)。

输入格式

N(N 堆纸牌,1 <= N <= 100)

A1 A2 … An (N 堆纸牌,每堆纸牌初始数,l<= Ai <=10000)

输出格式

所有堆均达到相等时的最少移动次数。

思路

设a[i]为第I堆纸牌的张数(0<=I<=n),v为均分后每堆纸牌的张数,s为最小移动次数。

我们用贪心算法,按照从左到右的顺序移动纸牌。如第I堆的纸牌数不等于平均值,则s加1,分两种情况移动:

1.若a[i]>v,则将a[i]-v张从第I堆移动到第I+1堆;

2.若a[i]<v,则将v-a[i]张从第I+1堆移动到第I堆。

代码


#include <bits/stdc++.h>
using namespace std;

int main() {
	int c[500];
	int n, sum = 0;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> c[i];
		sum += c[i];
	}
	int avg = sum / n;
	int count = 0;
	for (int i = 0; i < n; i++) {
		if (c[i] != avg) {
			c[i + 1] += c[i] - avg;
			count++;
		}
	}
	cout << count << endl;	
}


青藤oj #10045. 零件分组

题目描述

某工厂生产一批棍状零件,每个零件都有一定的长度 Li和重量Wi 。现在为了加工需要,要将它们分成若干组,使每一组的零件都能排成一个长度和重量都不下降(若 i<j,则Li<=Lj ,Wi<=Wj )的序列。请问至少要分成几组?

输入格式

第一行为一个整数N(N<=1000) ,表示零件的个数。第二行有N 对正整数,每对正整数表示这些零件的长度和重量,长度和重量均不超过 。

输出格式

仅一行,即最少分成的组数。

思路

dp[i]=max(dp[j]+1,dp[i])

代码


#include<bits/stdc++.h>
using namespace std;
struct str
{
    int l,r;
}a[11000];
int n;
int dp[11000]={0},ans;
bool cmp(str x,str y)
{
    if(x.l==y.l) return x.r<y.r;
    return x.l<y.l;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].l>>a[i].r;
    }
    sort(a+1,a+1+n,cmp);
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<i;j++)
        {
            if(a[j].r>a[i].r)
            {
                dp[i]=max(dp[j]+1,dp[i]);
            }
        }
        ans=max(dp[i],ans);
    }
    cout<<ans+1;
}

青藤oj #10040. 纪念品组合

题目描述

元旦快到了,校学生会让乐乐负责新年晚会的纪念品发放工作。为使得参加晚会的同学所获得的纪念品价值相对均衡,他要把购来的纪念品根据价格进行分组,但每组最多只能包括两件纪念品,并且每组纪念品的价格之和不能超过一个给定的整数。为了保证在尽量短的时间内发完所有纪念品,乐乐希望分组的数目最少。你的任务是写一个程序,找出所有分组方案中分组数最少的一种,输出最少的分组数目。

输入格式

输入文件包含n+2 行: 第 1 行包括一个整数w ,为每组纪念品价格之和的上限。 第 2 行为一个整数n ,表示购来的纪念品的总件数。 第 3~ n +2 行每行包含一个正整数 p i (5 <= p i <= w ),表示所对应纪念品的价格。

输出格式

输出文件仅一行,包含一个整数,即最少的分组数目。

思路

贪心,没啥好说的。。。

代码

#include<bits/stdc++.h>
using namespace std;

bool cmp(int a, int b)
{
	return a < b;
}
int main()
{
	int limit, num, s = 0;
	cin >> limit >> num;
	vector<int> money;
	int temp;
	for (int i = 0; i < num; i++)
	{
		cin >> temp;
		money.push_back(temp);
	}
	sort(money.begin(), money.end(), cmp);
	for (int i = 0; i < num; i++)
	{
		for (int j = num - 1; j >= i, money[i] != 0; j--)
		{
			if (j == i)
			{
				s++;
				break;
			}
			if (money[j] != 0 && money[i] != 0 && money[i] + money[j] <= limit)
			{
				s++;
				money[j] = 0;
				break;
			}
		}
	}
	cout << s;
	return 0;
}



青藤oj #10036. 排队接水

题目描述

有n个人在一个水龙头前排队接水,假如每个人接水的时间为Ti,请编程找出这n个人排队的一种顺序, 使得n个人的平均等待时间最小。 n<=1000,等待的时间小于等于1000

输入格式

输入文件共两行,第一行为n;第二行分别表示第 1 个人到第n个人每人的接水时间T1,T2,…,Tn,每 个数据之间有 1 个空格。

输出格式

输出有一行,最少平均排列方案下的平均等待时间(输出结果精确到小数点后两位)。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
int main()
{
    scanf("%d",&n);
    ll sum=0;
    int *a=new int[n+1];
    for(int i=0;i<n;i++)
    {
        scanf("%I64d",&a[i]);
    }
    sort(a,a+n);
    for(int i=0;i<n;i++)
    {
        sum+=a[i]*(n-i);
    }
    printf("%.2lf\n",(1.0*sum/n));
}


青藤oj #10081. 活动选择

题目描述

学校在最近几天有n个活动,这些活动都需要使用学校的大礼堂,在同一时间,礼堂只能被一个活动使用。由于有些活动时间上有冲突,学校办公室人员只好让一些活动放弃使用礼堂而使用其他教室。

现在给出n个活动使用礼堂的起始时间bi和结束时间ei(bi < ei<=32767),请你帮助办公室人员安排一些活动来使用礼堂,要求安排的活动尽量多。

输入格式

第一行一个整数n(n<=1000); 接下来的n行,每行两个整数,第一个bi,第二个是ei(bi < ei<=32767)

输出格式

输出最多能安排的活动个数

代码


#include<bits/stdc++.h>
using namespace std;
int beginn[1001],endd[1001];
int n,sum=0;
void qsort(int,int);
void slove();
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&beginn[i],&endd[i]);
    }
    qsort(1,n);
    slove();
    return 0;
}
void qsort(int x,int y)
{
    int l=x,r=y,m=endd[(x+y)/2];
    while(l<=r)
    {
    while(endd[l]<m)l++;
    while(endd[r]>m)r--;
    if(l<=r)
    {
        int m=endd[l];endd[l]=endd[r];endd[r]=m;
        int n=beginn[l];beginn[l]=beginn[r];beginn[r]=n;
        l++;r--;
    }
    }
    if(l<y)qsort(l,y);
    if(r>x)qsort(x,r);
}
void slove()
{
    int lastt=-1;
    for(int i=1;i<=n;i++)
    {
        if(beginn[i]>=lastt)
        {
            sum++;
            lastt=endd[i];
        }
    }
    printf("%d",sum);
}


青藤oj #10082. 整数区间

题目描述

给n个区间,形式为[a, b],a和b均为整数,且a < b。求一个最小的整数点的集合,使得每个区间至少 1 个元素属于这个集合。求这个集合的元素个数。

输入格式

第1行:1个整数n(1 <= n <= 10000)接下来n行,每行2个整数,表示区间的左右端点a, b(0 <=a < b <= 10000)

输出格式

第1行:1个整数,表示集合的元素的个数

代码


#include<bits/stdc++.h>
using namespace std;
struct range
{
  int from,to;
}a[10000];
 bool cmp(range x,range y) 
 {
     return x.to<y.to;
 }
 int main()
 {
     int n,i,sum=0;
     cin>>n;
     for(i=0;i<n;i++)
        cin>>a[i].from>>a[i].to;
     sort(a,a+n,cmp);
     int x;
     for(i=0,x=-1;i<n;i++)     
     {                        
 
         if(x>=a[i].from)   continue; 
         x=a[i].to;                    
         sum++;        
     }
     cout<<sum;
     return 0;
 }
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值