UVA822 ac要点

首先题目里的每个人按优先级选工作的表达是不准确的,正确的说法是:让每个人都尽量选自己最熟悉的工作,并且如果一个人没找到自己最熟悉的工作的话,则要把挑选机会让给下一个人,而不是继续找自己下一个熟悉的工作.

举个例子

假定每个人的技能数都是5个,那么最坏情况下要经过5轮才能每个人都分配到工作,

也就是第一轮让每个人都尽量选自己最熟悉的工作,如果都找到了,则循环结束。否则没有找到工作的人进行第2轮挑选,

选的是自己第二熟悉的工作,依次类推.

给个实际数据,假定有两个业务员A和B,各自的技能列表为

A:{4 3 1 2}

B:{1 2 3}

那么,当有工作2要被分配的时候,最需要经过两轮挑选,最终分配给B

下面是测试数据

15
1 68 36 23 2
2 9 6 19 60
3 67 10 6 49
4 49 44 23 66
5 81 8 18 35
6 99 85 85 75
7 94 75 94 96
8 29 7 67 28
9 100 95 11 89
10 29 16 10 29
11 32 55 10 15
12 70 48 4 84
13 100 36 63 73
14 42 93 28 47
15 100 35 2 73
3
1 13 1 2 3 4 5 6 7 8 9 11 12 13 14
2 10 2 3 4 5 9 10 11 12 14 15
3 11 1 2 3 4 5 6 7 9 13 14 15
0

最终花费的时间为13899

下面是ac代码

 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#ifdef _DEBUG
#include 
#endif // _DEBUG
using namespace std;

#ifdef _DEBUG
ifstream ifs;
ofstream ofs;

const int UVA_PROBLEM_NO = 822;
void redirect_input()
{
	ostringstream oss;
	oss << "uva" << UVA_PROBLEM_NO << "_in.txt";
	ifs.open(oss.str().c_str());
	cin.rdbuf(ifs.rdbuf());
}

void redirect_output()
{
	ostringstream oss;
	oss << "uva" << UVA_PROBLEM_NO << "_out.txt";
	ofs.open(oss.str().c_str());
	cout.rdbuf(ofs.rdbuf());
}

#endif


void main_proc();
int main() {
#ifdef _DEBUG

	redirect_input();
	redirect_output();


#endif // _DEBUG
	main_proc();
#ifdef _DEBUG
	ifs.close();
	ofs.close();
#endif
	return 0;
}
struct Topic
{
	int tid;
	int num;
	int t0;
	int t;
	int dt;
};



struct StaffInfo
{
	int last_start_time;  //每个人最后一个工作的开始时间
	int last_end_time;    //每个人最后一个工作的结束时间
	vector skills;

	StaffInfo(const StaffInfo & other)
		:last_end_time(other.last_end_time)
		,last_start_time(other.last_start_time)
		,skills(other.skills)
	{
		
	}

	StaffInfo()
		:
		last_end_time(0)
		,last_start_time(0)
		
	{

	}

};

typedef pair Event; //记录每个事件发生的时间和事件编号
typedef pair FreeStatff; //记录每个空闲的员工,第一坐标为上一个工作开始的时间,第二个为员工编号

struct Log {
	int arrive; //事件到达的时间
	int tid; //事件编号
	int t0;  //实际被处理的时间
	int pid; //解决这个问题的人

	Log(const Event& work, int t0, int pid)
		:arrive(work.first)
		, tid(work.second)
		, t0(t0)
		, pid(pid)
	{

	}

	bool operator< (const Log& other)const
	{
		if (t0 != other.t0)
			return t0 < other.t0;
		else if (arrive != other.arrive)
			return arrive < other.arrive;
		else
			return tid < other.tid;
	}

	Log(const Log& other) :
		arrive(other.arrive)
		, tid(other.tid)
		, t0(other.t0)
		, pid(other.pid)
	{

	}

	Log& operator=(const Log& other) {
		if (this != &other)
		{
			arrive = other.arrive;
			tid = other.tid;
			t0 = other.t0;
			pid = other.pid;
		}

		return *this;
	}
};

struct Scenario {
	map time_needed; //处理某个种类的请求所花的时间
	set events;  //记录每个事件发生的时间点和事件编号
	map staffs;

	int max_skill_num;

	int last_end_time; //最晚结束的工作时间,也是最终要输出的值
	set time_points; //可能发生调度的时间点


	set logs; //记录每个请求对应的人,用于调试
	
	bool read()
	{
		bool flag = true;
		if (flag=read_topics())
			read_staffs();

		return flag;
	}

	int get_process_time(int tid)const	{
		auto it = time_needed.find(tid);
		assert(it != time_needed.end());
		return it->second;
	}

	bool read_topics() {
		int n;
		cin >> n;
		
			for (int i = 0;i < n;++i)
			{
				int tid = 0;
				int num = 0;;
				int t0 = 0;;
				int t = 0;
				int dt = 0;
				cin >> tid >> num >> t0 >> t >> dt;
				set empty_staffs;
				for (int j = 0;j < num;++j, t0 += dt) {
					time_needed[tid] = t;
					Event event = make_pair(t0, tid);
					events.insert(event);
					time_points.insert(t0);
				}
			}
		
		return n > 0;
	}

	void read_staffs()
	{
		max_skill_num = 0;
		int n;
		cin >> n;
		
		for (int i = 0;i < n;++i) {
			int pid;
			cin >> pid;
			int m;
			cin >> m;

			if (m>max_skill_num)
				max_skill_num = m;
			
			for (int j=0;j> x;
				staffs[pid].skills.push_back(x);
			}
		}
	}

	//得到t0时刻在休息的职员列表
	void get_wait_staffs(int t0, set& wait_queue) {
		for (auto& e:staffs)
		{
			int tp = e.second.last_end_time;
			if (tp <= t0)
				wait_queue.insert(make_pair(e.second.last_start_time, e.first));
		}
	}

	//得到t0时刻尚待处理的事件列表,it 指向这个列表的结尾
	void get_wait_events(int t0,set& wait_event)
	{
		auto it = events.begin();
		while (it != events.end())
		{
			int time = it->first;
			if (time > t0)
				break;
			else {
				wait_event.insert(*it);
				it = events.erase(it);
			}
		}
	}

	void simulate(int t0)
	{
#ifdef  _DEBUG
		//cout << "\nbegin at tp " << t0 << endl;
#endif //  _DEBUG

		set wait_events;
		get_wait_events(t0, wait_events);



		if (!wait_events.empty())
		{
#ifdef  _DEBUG
#if 0
			cout << "wait_events: " << endl;
			int n = 0;
			for (auto e : wait_events)
			{
				cout << "(" << e.first << "," << e.second << ") ";
				++n;
				if (n % 10 == 0)
					cout << endl;
			}
			cout << endl;
#endif
#endif //  _DEBUG

			set free_staffs;
			get_wait_staffs(t0, free_staffs);



			if (free_staffs.size() > 0) {
#ifdef  _DEBUG
#if 0
				cout << "free_staffs: " << endl;
				int n = 0;
				for (auto e : free_staffs)
				{
					cout << "(" << e.first << "," << e.second << ") ";
					++n;
					if (n % 10 == 0)
						cout << endl;
				}
				cout << endl;
#endif
#endif //  _DEBUG
				allocate_work(t0, free_staffs, wait_events);
			}

			//把无人处理的事件再放回队列里
			for (const auto & e : wait_events)
				events.insert(e);
		}

#ifdef  _DEBUG
		//cout << "end at tp " << t0 << endl <second;
	}

	const StaffInfo& get_staff(int pid)const {
		auto it = staffs.find(pid);
		assert(it != staffs.end());
		return it->second;
	}

	void allocate_work(int t0,set& free_staffs
		, set& works) {

		//注意选工作的时候轮数按最大技能数为准,也就是第一轮让每个人都先优先做其最熟悉的工作,
		//如果第一轮结束后仍有未分配到工作的人,则让这些人再进来做其第二熟悉的工作,以此类推
		
		for (size_t i=0;isecond;
				const StaffInfo& staff = get_staff(pid);

				bool flag = false;

				if (isecond == tid) {
							allocate_work(t0, pid, *it2);  //分配工作
							works.erase(it2);
							flag = true;
							break;
						}
					}
				}
				if (flag)  //当前技术员找到工作的话,则把它从空闲列表里删除
					it = free_staffs.erase(it);
				else
					++it;
			}
		}
	}

	void allocate_work(int t0, int pid, const Event & work) {
		StaffInfo& staff = get_staff(pid);
		int tid = work.second;
		int need_time = get_process_time(tid);
		staff.last_start_time = t0;
		staff.last_end_time = t0 + need_time;
		time_points.insert(staff.last_end_time);
		if (staff.last_end_time > last_end_time)
			last_end_time = staff.last_end_time;

#ifdef _DEBUG
		Log log(work,t0,pid);
		logs.insert(log);
		
#if 0
		cout << "topic " << tid << " arrived at time " << work.first
			<< " is processed by " << pid << " at time " << t0
			<< ",will ended at time " << staff.last_end_time << endl;
#endif
#endif // _DEBUG

	}


	void print()const {
		for (auto& e:events)
			cout << e.first << " " << e.second << endl;
		
		for (auto& e : staffs) {
			cout << e.first;
			for (auto & f:e.second.skills)
				cout << " " << f;
			cout << endl;
		}
	}

	void print_log()const 
	{
		for (const auto& e : logs)
		{
			const int t = get_process_time(e.tid);
			const int end = e.t0 + t;
			cout << e.t0 << " " << e.tid 
				//<< " " << e.arrive
				<< " " << e.pid 
				//<< " " << t 
				//<< " " << end
				<

下面是部分中间日志,以便对拍.第一列为时间点,第二列为工作编号,第3列为职员编号,比如第2行7 8 1就表示在时刻7,将工作8分配给了职员1.

6 2 2
7 8 1
8 5 3
25 3 2
31 10 2
35 15 3

 

你可能感兴趣的:(算法)