Homework Introduction

贪心

课程讲义链接: http://oj.mqcoj.cn:5000/paste/show/VzZXbx10fZdsPv8a

/*
  对于每一个要插入的数字
  0. 先从小到大排序
  1.先找现有的分组中,有没有这个数可以插入的地方
  2. 如果有多个可插入的为止,选择长度最小的一个组
  3. 如果没有,新建立一个组别
 */

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, a[N];
struct node {
	// num 记录这个组别的数字的数量
	// sl 队列的最后一个数字
	int num, sl;
};
node team[N];   // 用来记录组别的信息
int mark; // 记录组别的数量
// map[a[i]]  以  a[i] 结尾的组别在优先队列中的编号为 map[a[i]]
map<int, int> mp;
// q[i] 以  i 结尾的
// 优先队列记录 <队员数量,组别编号>
priority_queue<pair<int, int> > q[N];  // 优先出队员数量最少的,前面加负号
int tot; // 记录优先队列的组别
void insert(int k) {
	// 现在要插入 k
	if (mp[k - 1] == 0) { // 当前没有以 k-1 结尾的
		++mark; // 新增一个组别,记录
		team[mark].num = 1;
		team[mark].sl = k; // 当前数字以 k  结尾
		// 先去判断有没有以 k 结尾的
		if (mp[k] == 0) {
			tot++;
			mp[k] = tot;
			q[tot].push({-1, mark});   // 记录他的值和他的组别
		} else {
			q[mp[k]].push({-1, mark}); // 放在之前的优先队列中
		}
	} else { // 有以 k -1 结尾的队列
		int t = mp[k - 1];
		int top = q[t].top().second; // 获取到以 k-1 结尾的队列中数量最小的的在 team 数组中的编号
		q[t].pop();
		if (q[t].size() == 0) mp[k - 1] = 0; // 当前 k-1 只有一个,出完了,归0
		// 现在变成以 k 结尾
		team[top].num++;
		team[top].sl = k;
		// 放置到 以 k 结尾的队列中
		// 先去判断有没有以 k 结尾的
		if (mp[k] == 0) {
			tot++;
			mp[k] = tot;
			q[tot].push({-team[top].num, top});   // 记录他的值和他的组别
		} else {
			q[mp[k]].push({-team[top].num, top}); // 放在之前的优先队列中
		}
	}
}

int main() {
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> a[i];
	sort(a, a + n);
	for (int i = 0; i < n; i++)
		insert(a[i]);
	// 组别编号是从 0 开始的
	int ans = team[1].num;
	for (int i = 1; i <= mark; i++)
		ans = min(ans, team[i].num);
	cout << ans;
	return 0;
}

加工生产调度

//// 时间:产品a 机器,b 机器
//产品1  a1 10 , b1  21
//产品2  a2  5,  b2  3
//
//a1 + b1 大的在前面 , 作为一个贪心策略
//1 - 2:  10 + 21 + 3 = 34    正解
//2 - 1:  5 + 10 + 21 = 36
//
//反例??? , 找到一个策略,去找反例,看能不能推翻
//能推翻,策略肯定是错的,不能推翻,不一定是对的?
//产品1  a1  10 , b1  4
//产品2  a2  5,  b2  6
//1 -2 :10 + 5 + 6  = 21
//2 -1 :5 + 10 + 4 = 19    正解
//
//加工产品,先在A 上面,再在B 上面
//尽快从 A 走到B,能更快完成,
//
//N1 表示  a<b 的任务列表 
//  大家都是  a<b  ,先完成谁?????? 优先完成 a 小的
//a1 5  b1 8
//a2 4  b2 8
//1+2 : 5+8+8
//2+1 : 4+8+8


//N2 表示 a>b 的任务列表, 优先完成 b 大的
// a1 10  b1 8
//// a2 10  b2 9
//1+2: 10 + 10 + 9
//2 + 1 : 10 + 10 + 8


//最优的策略是  N1 + N2

//
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;

struct node {
	int a, b;
	int id;
};

bool cmp1(node a, node b) {
	return a.a < b.a;
}

bool cmp2(node a, node b) {
	return a.b > b.b;
}

node a[N], b[N];
int la, lb;
int n, t[N];

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> t[i];
	for (int i = 1; i <= n; i++) {
		int tmp;
		cin >> tmp;
		if (tmp <= t[i]) {
			b[++lb].a = t[i];
			b[lb].b = tmp;
			b[lb].id = i;
		} else {
			a[++la].a = t[i];
			a[la].b = tmp;
			a[la].id = i;
		}
	}
	sort(a + 1, a + 1 + la, cmp1);
	sort(b + 1, b + 1 + lb, cmp2);
	// 计算时间
	// 一个任务是有 a 的时间和 b 的时间
	int cnt = 0;
	int ta = 0, tb = 0; // 记录上一个任务的完成时间
	for (int i = 1; i <= la; i++) {
		t[++cnt] = a[i].id;  // 完成顺序
		ta += a[i].a;
		// 1.
		// tb = 10 , 上一个任务在 b 机器上的完成时间
		// ta = 9 ,  当前任务在 a 机器上的完成时间,
		// 任务准备好了,机器没有准备好
		// 当前任务在 b 机器上的开始时间,  10

		// tb = 10 , 上一个任务在 b 机器上的完成时间
		// ta = 15 ,  当前任务在 a 机器上的完成时间,
		// 机器准备好了,但是任务没有准备好
		// 当前任务在 b 机器上的开始时间, 15

		tb = max(ta, tb) + a[i].b;
	}

	for (int i = 1; i <= lb; i++) {
		ta += b[i].a;
		tb = max(ta, tb) + b[i].b;
		t[++cnt] = b[i].id;  // 完成顺序
	}

	cout << tb << endl;
	for (int i = 1; i <= n; i++)
		cout << t[i] << " ";

	return 0;
}

序列排序

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
#define int long long
int n, a[N], c[N], tmp[N];
bool vis[N];
int k = 1e9;// 全局最小值
int sum, cnt, minn, ans; // 环内的和,个数,最小值

void dfs(int i) {
	sum += a[i];
	minn = min(minn, a[i]);
	cnt++;
	vis[i] = 1;
	if (vis[c[i]])
		return ;
	dfs(c[i]);
}

signed main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		tmp[i] = a[i];
		k = min(k, a[i]);
	}
	sort(tmp + 1, tmp + 1 + n);

	for (int i = 1; i <= n; i++)
		c[i] = lower_bound(tmp + 1, tmp + 1 + n, a[i]) - tmp;

	for (int i = 1; i <= n; i++) {
		if (vis[i])
			continue;
		sum = 0, cnt = 0, minn = 1e9;
		dfs(i);
		int t1 = sum + minn * (cnt - 2);
		int t2 = sum + k * (cnt + 1) + minn;
		ans += min(t1, t2);
	}
	cout << ans;
	return 0;
}

Problem

Please claim the assignment to see the problems.
Status
Live...
Problem
45
Open Since
2025-11-2 0:00
Deadline
2026-11-2 23:59
Extension
24 hour(s)