[coci2015-2016 coii] dijamant【图论】

传送门:http://www.hsin.hr/coci/archive/2015_2016/

进去之后的最下面的国家赛。顺便说一句,dijamant是克罗地亚语的“钻石”的意思。

官方题解是说压位的暴力可以AC,但是给出了一个更棒的算法,是这样的:只考虑如何判断“diamond”,因为前两个子任务实在是太容易了。设Pi为当前声明的类继承的第i个类。那么当声明一个类时,先读取其继承的类,读进P,然后对P按“由刚刚声明的类到最早声明的类”排序,换句话说,就是从大到小排(当然了,如果使用stl的map,一定是越早成功声明的类,编号越小)。然后,维护一个布尔型的R数组,若Ri为true,表明当前正在声明的类可以从第i个类派生(derive)出来。那么分两种情况:

①,若Pi已经被标记,即R[Pi] = true,则直接ignore

②,若Pi未被标记,则将所有可以派生出Pi的类全部标记,并且如果某个可以派生出Pi的类已经被标记,则说明出现了一个diamond,声明类失败。

上述内容仔细想想、画画图就有了,确实挺巧妙的。

#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <cstring>

const int maxn = 1005, maxe = 1000006;

int head[maxn], to[maxe], next[maxe], lb;
int n, P[maxn], idx, cnt;
char R[maxn];
std::string str, now;
std::map<std::string, int> mp;

inline void ist(int aa, int ss) {
	to[lb] = ss;
	next[lb] = head[aa];
	head[aa] = lb;
	++lb;
}
bool cmp(const int aa, const int ss) {
	return aa > ss;
}

int main(void) {
	freopen("dijamant.in", "r", stdin);
	freopen("dijamant.out", "w", stdout);
	memset(head, -1, sizeof head);
	memset(next, -1, sizeof next);
	std::cin >> n;
	char flag;
	int tem;
	int nn = n;
	while (nn--) {
		flag = 0;
		std::cin >> now;
		if (mp.count(now)) {
			std::cout << "greska\n";
			flag = 1;
		}
		std::cin >> str;
		
		if (flag) {
			while (1) {
				std::cin >> str;
				if (!strcmp(str.c_str(), ";")) {
					break;
				}
			}
			continue;
		}
		
		idx = 0;
		memset(R, 0, sizeof R);
		while (1) {
			std::cin >> str;
			if (!strcmp(str.c_str(), ";")) {
				break;
			}
			if (!flag) {
				if (!mp.count(str)) {
					flag = 1;
					std::cout << "greska\n";
				}
				else {
					P[idx++] = mp[str];
				}
			}
		}
		if (flag) {
			continue;
		}
		
		std::sort(P, P + idx, cmp);
		for (int i = 0; i < idx; ++i) {
			tem = P[i];
			if (R[tem]) {
				P[i] = -1;
				continue;
			}
			for (int j = head[tem]; j != -1; j = next[j]) {
				if (R[to[j]]) {
					flag = 1;
					std::cout << "greska\n";
					goto spe;
				}
				else {
					R[to[j]] = 1;
				}
			}
		}
		spe:;
		if (flag) {
			continue;
		}
		
		for (int i = 0; i < cnt; ++i) {
			if (R[i]) {
				ist(cnt, i);
			}
		}
		for (int i = 0; i < idx; ++i) {
			if (P[i] != -1) {
				ist(cnt, P[i]);
			}
		}
		std::cout << "ok\n";
		mp[now] = cnt;
		++cnt;
	}
	return 0;
}

  

posted @ 2017-03-28 20:37  ciao_sora  阅读(276)  评论(0编辑  收藏  举报