Xtreme 10.0 - Painter's Dilemma

Xtreme 10.0 - Painter's Dilemma

题目:

https://www.hackerrank.com/contests/ieeextreme-challenges/challenges/painters-dilemma


题意:

        Bob是一名粉刷匠,他的工作是帮别人粉刷房子的墙壁。Bob只有两把刷子,在工作时,需要根据工序给房子刷不同的颜色。如果要刷的颜色和刷子现有的颜色都不同,Bob必须挑选一把刷子进行清洗并重新上色。现给出房子粉刷工序颜色的序列,求出一种给刷子换色的方案,使得Bob给刷子换色的次数最少,并输出换色的次数。


输入:

第一行 输入 t,代表有t个测试用例,其中 1 <= t <= 5。

第二行输入 n,代表粉刷序列的长度,其中 1 <= n <= 500。

第三行输入n个数c[1], c[2], ..., c[n - 1],代表需要刷墙颜色的序列,其中 1 <= c[i] <= 20,c[i]每个整数的取值代表一种颜色。

接下来是第2个测试用例的n.....


输出:Bob给刷子换色的最少次数。


测试用例:

输入:

2
5
7 7 2 11 7
10
9 1 7 6 9 9 8 7 6 7


输出:

3

6


解释:

        对于第一个测试用例,刷7号颜色时,Bob给第一把刷子上7号色;刷第二个7号色时,不用换色;刷2号色时,Bob给第二把刷子上2号色;刷11号色时,Bob清洗第二把刷子并重新上11号色;刷最后一个7号色时,Bob直接用第一把刷子,不用换色。因此总共换色次数是3。


思路:

        这道题实际上是操作系统中页面置换的问题。Bob的两把刷子可以看做内存的页数,颜色序列可以看做进程要访问的页面,Bob重新给刷子上色可以看做缺页中断。由于要上色的颜色序列是已知的,因此可以使用页面调度的OPT算法来解决。该算法的思想是,当发生缺页中断时,把将来距离现在最远的访问页面调出内存。
        注意,在Bob需要给刷子时,需要找到将来最远使用到的颜色,来进行置换。该搜寻的方法可以通过遍历颜色序列来求得。但时间复杂度为O(n^2)。由于题目中颜色的种类是有限的(20种),因此可以在一开始对颜色序列进行预处理,先创建20个颜色队列表,将每种颜色的出现的位置存到对应的队列中,则在需要查找最远出现颜色的时,直接查表就可以了。这样可以将时间复杂度降为O(n)。

代码:

#include <cstdio>
#include <vector>
#include <iostream>
#include <queue>
#include <algorithm>

using namespace std;

#define EMPTY  -1

void oneCase() {
	int n = 0;
	cin >> n;
	vector<int> seq(n);
	int cache[2] = { EMPTY, EMPTY };
	for (int i = 0; i < n; i++) {
		cin >> seq[i];
	}

	vector<queue<int>> table(21);
	for (int i = 0; i < n; i++) {
		table[seq[i]].push(i);
	}

	int resCount = 0;

	for (int i = 0; i < n; i++) {
		if (seq[i] != cache[0] && seq[i] != cache[1]) {
			resCount++;
			if (cache[0] == EMPTY) {
				cache[0] = seq[i];
				table[seq[i]].pop();
				continue;
			}
			if (cache[1] == EMPTY) {
				cache[1] = seq[i];
				table[seq[i]].pop();
				continue;
			}
			int tmp0 = table[cache[0]].empty() ? 501 : table[cache[0]].front();
			int tmp1 = table[cache[1]].empty() ? 501 : table[cache[1]].front();
			if (tmp0 < tmp1) {
				//out 1;
				cache[1] = seq[i];
			} else {
				//out 0;
				cache[0] = seq[i];
			}
		}
		table[seq[i]].pop();
	}

	cout << resCount << endl;

}

int main() {
	int caseCount = 0;
	cin >> caseCount;
	while (caseCount) {
		oneCase();
		caseCount--;
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值