C语言(CED)智力大冲浪——贪心算法第一题

一、题目大意

小伟报名参加中央电视台的智力大冲浪节目,本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元。先不要太高兴!因为这些钱还不一定都是你的!接下来主持人宣布了比赛规则:首先,比赛时间分为n个时段(n≤500),它又给出了很多小游戏,每个小游戏都必须在规定期限ti前完成(1≤ti≤n)。如果一个游戏没能在规定期限前完成,则要从奖励费m元中扣去一部分钱wi,wi为自然数,不同的游戏扣去的钱是不一样的。当然,每个游戏本身都很简单,保证每个参赛者都能在一个时段内完成,而且都必须从整时段开始。主持人只是想考考每个参赛者如何安排组织自己做游戏的顺序。作为参赛者,小伟很想赢得冠军,当然更想赢取最多的钱!注意:比赛绝对不会让参赛者赔钱!

输入:

输入文共4行。

第1行为m,表示一开始奖励给每位参赛者的钱;

第2行为n,表示有n个小游戏;

第3行有n个数,分别表示游戏1到n的规定完成期限;

第4行有n个数,分别表示游戏1到n不能在规定期限前完成的扣款数。

【输出】输出文件仅1行,表示小伟能赢取最多的钱

【sample input】

  10000

  7

  4   2    4   3   1   4   6

  70  60   50  40  30  20  10

【sample output】

  9950

二、大致思路

        这道题数据有很多,但是要学会排除掉多余干扰因素。因为要让剩余的奖金最大化,所以我们可以按照未完成游戏时所扣金额的大小排序(这里我按照从大到小进行排序),首先选择进行扣钱金额大的游戏。那么问题来了,每个游戏都有固定的截止时间,有很多扣钱大的游戏相互冲突,怎么办?相信很多人都会卡在这个问题上。我们可以通过以下方法实现所得奖金最大化:我们按上述方法排序后,从左到右遍历,能在对应时间段完成的,就完成;不能在该时间段完成的,就找一个在该游戏截止时间之前的时间段完成游戏,如果找不到,则放弃。

        下面以一个具体的例子进行遍历:

        游戏截止时间: 4    2     4    3    1    4    6

        游行名称:        A    B    C    D   E    F   G

         所扣金额:      70  60   50  40  30  20  10

   为了方便起见,我在这里就统一用时刻代表何时完成游戏(时刻和时间段不一样)。如上表所示,从左到右对游戏进行遍历,我们在4s进行A游戏2S进行B游戏,下一个游戏本来要在4s进行,但是4S已经被占用了,所以要向下(游戏截止前)找一个空余时间去完成该游戏,在对时间向下遍历的时候发现3S没被占用,所以用3S进行C游戏继续遍历,遇到D游戏,但是3S已经被占用,同理对时间向下遍历:2S不行,1S可以,所以用1S进行D游戏继续对游戏向右遍历,遇到E游戏,本来在1S进行,但是被占用了,然后对时间向下遍历,在1S前没有空时间,所以就放弃E游戏。对游戏继续遍历,同理F游戏也得放弃,最后的G游戏可以进行。整个遍历的过程就是这样,复杂度N方。

三、具体实现

        我用C语言写的代码,在代码开头,定义一个数组,并初始化为0,用来对各个时间是否被使用进行标记,1为使用。然后定义一个game结构体,并设置f(finish代表游戏截止时间),d(decrease代表罚金),p(position代表有一是否进行1表示进行,0代表未进行)三个属性。之后就是照着之前的分析进行代码设计。

#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<iostream>
using namespace std;
int  m;//代表开始奖励给每位参赛者的钱
int  b[6000] = { 0 };//记录时间段是否被使用,使用标记为1
//定义一个游戏结构体,存储游戏的属性
struct game
{
	int f;//表示游戏1到n的规定完成期限
	int d;//表示游戏1到n不能在规定期限前完成的扣款数
	int p = 0;//1表示对应的游戏已完成,0表示未完成
};
//用bool函数对排序依据的因素进行选择
bool cmp(game f, game d)
{
	return f.d > d.d;//选择罚款项进行非增序排序
}
//此函数为计算最小扣款函数
int compu(int n, game a[])
{
	sort(a, a + n, cmp);//对罚款进行非递增排序
	int i, j;//循环变量
	//外层循环对已排好序的游戏,进行从左到右的遍历
	for (i = 0; i<n; i++)
	{
		//如果游戏对应的时间段没有被占用,则进行该游戏
		if (b[a[i].f] == 0)
		{
			a[i].p = 1;//对游戏中是否完成的属性进行修改,表明该游戏已完成
			b[a[i].f] = 1;//对游戏使用的时间段进行标记
			continue;//进行下一个游戏的判断
		}
		//游戏对应的时间段已被占用
		else
		{
			for (j = (a[i].f - 1); j >0; j--)
			{
				//表明找到空闲时间段完成本游戏
				if (b[j] == 0)
				{
					a[i].p = 1;//对游戏中是否完成的属性进行修改,表明该游戏已完成
					b[j] = 1;//对游戏使用的时间段进行标记
					break;
				}
				//表明未找到空闲时间段完成本游戏,继续循环找
				else
					continue;
			}
		}
	}
	return m;
}
int main()
{
	game a[6000];//定义游戏
	int n;//表示有n个小游戏
	cout << "请输入开始时奖励给每位参赛者的钱款金额:" << endl;
	cin >> m;
	cout << "请输入小游戏的个数:" << endl;
	cin >> n;
	int i = 0;//循环变量
	cout << "请输入每个游戏规定完成的期限:" << endl;
	for (i = 0; i <n; i++)
	{
		cin >> a[i].f;
	}
	cout << "请输入每个游戏不能在规定期限前完成的扣款数:" << endl;
	for (i = 0; i < n; i++)
	{
		cin >> a[i].d;
	}
	int sum = 0;//表示小伟的获奖金额
	sum = compu(n, a);
	for (i = 0; i < n; i++)
	{
		if (a[i].p == 0)
			sum = sum - a[i].d;
	}
	if (sum < 0)
		sum = 0;
	cout << "小伟最多得奖的金额数为:" << sum << endl;
	system("pause");
	return 0;
}

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
以下是基于 OpenSSL 库实现的 SM2 公钥加密算法 C 语言代码,供你参考: ```c #include <openssl/evp.h> #include <openssl/sm2.h> #define PUBKEY "04B8D9B4F5B7ACF0465E7B7A1F3E7C7A8C625A5D57F8B9D6D7E7B3C6EA2E8E7B8D2D0CED0C2BBD5C7B9D9B7A2D3D0C5C0B1A8D3ADA1BAC3CFA1AAE7" #define PLAINTEXT "Hello, world!" int main() { int ret = 0; int ciphertext_len = 0; unsigned char ciphertext[1024] = {0}; unsigned char pubkey[65] = {0}; unsigned char plaintext[1024] = {0}; unsigned char sm2_id[] = "1234567812345678"; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *pctx = NULL; /* 初始化 OpenSSL 库 */ OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); /* 从字符串中读取公钥 */ int pubkey_len = strlen(PUBKEY) / 2; for (int i = 0; i < pubkey_len; i++) { sscanf(PUBKEY + i * 2, "%2hhx", pubkey + i); } /* 创建 EVP_PKEY 对象 */ pkey = EVP_PKEY_new(); if (!pkey) { printf("EVP_PKEY_new failed\n"); goto done; } /* 设置 EVP_PKEY 对象的算法为 SM2 */ ret = EVP_PKEY_set_type(pkey, EVP_PKEY_EC); if (ret <= 0) { printf("EVP_PKEY_set_type failed\n"); goto done; } /* 从公钥字节数组中创建 EC_KEY 对象 */ EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_sm2); if (!ec_key) { printf("EC_KEY_new_by_curve_name failed\n"); goto done; } /* 从公钥字节数组中设置 EC_KEY 对象的公钥 */ ret = EC_KEY_oct2key(ec_key, pubkey, pubkey_len, NULL); if (ret <= 0) { printf("EC_KEY_oct2key failed\n"); goto done; } /* 将 EC_KEY 对象设置到 EVP_PKEY 对象中 */ ret = EVP_PKEY_set1_EC_KEY(pkey, ec_key); if (ret <= 0) { printf("EVP_PKEY_set1_EC_KEY failed\n"); goto done; } /* 创建 EVP_PKEY_CTX 对象 */ pctx = EVP_PKEY_CTX_new(pkey, NULL); if (!pctx) { printf("EVP_PKEY_CTX_new failed\n"); goto done; } /* 初始化 SM2 公钥加密上下文 */ ret = EVP_PKEY_encrypt_init(pctx); if (ret <= 0) { printf("EVP_PKEY_encrypt_init failed\n"); goto done; } /* 设置 SM2 公钥加密上下文的 ID */ ret = EVP_PKEY_CTX_ctrl_str(pctx, "set1_id", sizeof(sm2_id) - 1, (char *)sm2_id); if (ret <= 0) { printf("EVP_PKEY_CTX_ctrl_str(set1_id) failed\n"); goto done; } /* 公钥加密 */ ret = EVP_PKEY_encrypt(pctx, ciphertext, &ciphertext_len, (const unsigned char *)PLAINTEXT, strlen(PLAINTEXT)); if (ret <= 0) { printf("EVP_PKEY_encrypt failed\n"); goto done; } printf("Ciphertext: "); for (int i = 0; i < ciphertext_len; i++) { printf("%02X", ciphertext[i]); } printf("\n"); done: /* 释放资源 */ if (pctx) { EVP_PKEY_CTX_free(pctx); } if (pkey) { EVP_PKEY_free(pkey); } if (ec_key) { EC_KEY_free(ec_key); } /* 清除 OpenSSL 错误队列 */ ERR_clear_error(); return ret; } ``` 在上述代码中,我们首先从字符串中读取公钥,然后创建 EVP_PKEY 对象,并设置其算法为 SM2。接着,我们从公钥字节数组中创建 EC_KEY 对象,并将其设置到 EVP_PKEY 对象中。最后,我们创建 EVP_PKEY_CTX 对象,初始化 SM2 公钥加密上下文,并进行公钥加密操作。 需要注意的是,在实际使用 SM2 公钥加密算法时,需要针对具体的业务场景进行 ID 的设置,以保证加密结果的安全性。在本例中,我们将 ID 设置为固定值 "1234567812345678",仅供参考。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liO_Oil

打赏我,开启隐藏模式。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值