Extraordinarily Tired Students <UVa 12108>

这个题即给定睡眠和醒着的周期以及开始时在周期的多少分钟,

如果打算睡时发现一半以上的人都没睡那就不睡了,再过一个醒着的周期再看

(我觉得只要坚持了之后醒着的人就会一直比睡了的人多,,希望我没想错)

#include<iostream>
#include<fstream>
#include<vector>
#include<map>
#include<iomanip>

using namespace std;

// 用一个课程最长的情况来跳出循环
const int LL = 1000;

// 课程类用静态变量记录有多少人以及当前睡着的人数
struct Course
{
	static int student, sleepingStu;
};

// 静态成员赋初值
int Course::student = 0;
int Course::sleepingStu = 0;

// 学生类继承课程
struct Student :public Course
{
// 每一个学生的周期记录
	int aware, sleep, startTime;
	bool sleepstate, keepOn;

	Student(int a, int b, int c) :aware(a), sleep(b), startTime(c) 
	{
		if (startTime <= aware) sleepstate = 0; else { sleepstate = 1; sleepingStu++; } 
		keepOn = 0;
	}
// 重载输入
	friend istream& operator >> (istream& in, Student it) {
		in >> it.aware >> it.sleep >> it.startTime; return in;
	}

// 这个其实思路有点类似与Qt的Timer 
	void sleepOrNot(int now,int lastSecSleep) {
// 如果开始坚持直接跳出
		if (keepOn) { return; } 
// 没过一个睡眠周期后醒来
		else if ((now - 1 + startTime) % (aware + sleep) == 1) {
			if (sleepstate)sleepingStu--, sleepstate = 0;
		}
// 过一个清醒周期
		else if ((now - 1 + startTime) % (aware + sleep)- aware == 1) {
// 因为每个学生是同时判断人数决定睡或不睡,所以要避免过程中睡着学生的改变,所以传参来保证同时
			if (student - lastSecSleep > lastSecSleep) 
			{
				keepOn = 1; 
                if (sleepstate)sleepingStu--, sleepstate = 0;
			}
			else if (!sleepstate) { sleepingStu++; sleepstate = 1; }
		}
	}
};

int main()
{
	freopen("in.txt", "r", stdin);
	freopen("my_ans.txt", "w", stdout);
	int n; int round = 0;
	while (cin >> n) {
		if (n == 0) break;
		cout << "case " << ++round << ": ";
		Student::student = n;
		vector<Student> stu; for (int i = 0; i < n; i++) { int a, b, c; cin >> a >> b >> c; stu.push_back({ a,b,c }); };

// 判断是否一开始就没人睡
		bool goodclass = 1; for (auto i : stu) if (i.sleepstate == 1) goodclass = 0;
		if (goodclass) 
		{ cout << "1\n"; continue; }

		int now = 1;
		while (true)
		{
			now++;
			if (now > LL) { now = -1; break; }
			vector<Student>::iterator it = stu.begin();
			int lastSecSleep = it->sleepingStu;
			while (it != stu.end()) { it->sleepOrNot(now, lastSecSleep); it++; }
			if (!Student::sleepingStu) break;
		}
		cout << now << endl;

	}
	return 0;
}

这个题我一开始的思路就是取余循环周期,但这样的效率太低

中间有几个Debug的点:

1. for(auto i: stu) 是创建一个临时变量对stu里的数据拷贝,在成员函数中修改后不会记录到stu对象的数据成员

2. 学生是同时判断的,用静态成员函数能保证共享修改,但是不能在循环时使先进入循环的影响后续,所以要传参他们判断时睡的人

3. 判断是否开始时就没人睡,否则如果now 从1开始遍历可能对初始状态进行改变

本题我的思路大致是这样,与Debug里的几万组数据对比仍会有不对的answer, 但大多还是能AC

仅记录一下自己的思路,后续再改...


好吧...看了一下别人的代码,我怎么能把问题复杂化成这样...

大佬永远是简化问题,小白是把简单问题复杂化还觉得自己写了内容...

本题即利用数组记录状态更新即可,本质没当数组走完一整个周期则回到醒着的时候,或者当走完一个醒着的周期发现不能睡则归零

#include<iostream>
using namespace std;

// 用一个大数跳出循环
const int LL = 1000;
// 存储对应周期
int awake[11], sleep[11], timer[11];
int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("my_ans.txt", "w", stdout);
	int n,round = 0;
	while (cin >> n) {
		if (n == 0) break;
		cout << "Case " << ++round << ": ";
		int sec = 1;
		for (int i = 0; i < n; i++)cin >> awake[i] >> sleep[i] >> timer[i];

		for (sec = 1; sec <= LL ; sec++)
		{
			int wake = 0; // 每一次重新计算醒着的人
			for (int i = 0; i < n; i++)
			{
				if (awake[i] >= timer[i]) wake++;
			}
			if (wake == n) { cout << sec << endl; break; }
			for (int i = 0; i < n; i++) {
// 走完一次循环或不睡
				if (timer[i] == awake[i] + sleep[i] || timer[i] == awake[i] && wake >= n - wake)
					timer[i] = 0;
				timer[i]++;
			}
// 跳出的结果
			if (sec == LL) { cout << "-1" << endl; break; }
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值