[CSP-S模拟测试]:循环依赖(拓扑)

题目传送门(内部题148)


输入格式

  每个测试点第一行为一个正整数$T$,表示该测试点内的数据组数。
  接下来$T$组数据,每组数据第一行一个正整数$n$,表示有引用单元格进行计算的单元格数,接下来$n$行,每行第一个字符串为该单元格编号,接下来若干个字符串表示该单元格引用的单元格编号。


输出格式

  对于每一组测试数据,若有循环依赖,则输出$Yes$,否则输出$No$。


样例

样例输入:

3
1
AA13 AA13
3
B1 A1 A2
C1 B1 A1
A2 C1 A1
4
B1 A1
C1 B1 A1
D1 C1 B1 A1
E1 D1 C1 B1 A1

样例输出:

Yes
Yes
No


数据范围与提示

样例解释:

  第一组数据中,$AA13$单元格引用自身,构成了自循环依赖。
  第二组数据描述了题面中的例子。
  第三组数据中,$B1$引用了$A1$,$C1$引用了$B1$和$A1$,以此类推到$E1$,每一个单元格只会引用在该单元格之前列的单元格的值,因此不会构成循环依赖。

数据范围:

  对于$20\%$的数据,有$1\leqslant n\leqslant 10$。
  对于$50\%$的数据,有$1\leqslant n\leqslant 100$。
  对于另外$30\%$的数据,每个单元格至多引用一个单元格。
  对于$100\%$的数据,有$1\leqslant n\leqslant 30,000$,单元格编号为长度不超过$10$的字符串,每个单元格都引用不超过$10$个单元格(计重数,下同),每组数据中单元格编号的数量$\leqslant 90,000$,每个测试点中单元格编号的总数量不超过$450,000$,在任意一组数据中,每行第一个单元格编号不重复,但每个单元格所引用的单元格编号可能重复。


题解

玄学读入,离散化,建图,拓扑,一遍过样例!

一脸懵逼……

 

发现旁边同学也都是这样额。

其实

 

$\rightarrow$$=$

出题人居然用$Windows$造数据!!!

换行附在$NOILinux$下是\n而在$Windows$下是\r。

剩下的就很裸了,不过如果你想用$tarjan$判环我也不拦你。

时间复杂度:$\Theta(m)$($m$表示依赖关系数)。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
unordered_map<unsigned long long,int>mp;
struct rec{int nxt,to;}e[200001];
int head[100001],cnt;
int n;
char ch[20];
int top,tot;
int du[100001];
queue<int> q;
unsigned long long hsh[500001];
unsigned long long hd[100001];
vector<unsigned long long>son[100001];
void pre_work()
{
	mp.clear();cnt=top=tot=0;
	memset(head,0,sizeof(head));
	memset(son,0,sizeof(son));
	memset(du,0,sizeof(du));
}
unsigned long long get()
{
	int len=strlen(ch+1);unsigned long long res=0;
	for(int i=1;i<=len;i++)res=res*131+ch[i]-'0';
	return res;
}
void add(int x,int y)
{
	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	head[x]=cnt;
}
bool topsort()
{
	int res=0;
	for(int i=1;i<=tot;i++)if(!du[i]){q.push(i);res++;}
	while(q.size())
	{
		int x=q.front();q.pop();
		for(int i=head[x];i;i=e[i].nxt)
		{
			du[e[i].to]--;
			if(!du[e[i].to]){res++;q.push(e[i].to);}
		}
	}
	return res==tot;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		pre_work();
		for(int i=1;i<=n;i++)
		{
			scanf("%s",ch+1);
			hd[i]=get();
			hsh[++top]=hd[i];
			char c=getchar();
			while(c!='\r')
			{
				scanf("%s",ch+1);
				hsh[++top]=get();
				son[i].push_back(hsh[top]);
				c=getchar();
			}
		}
		sort(hsh+1,hsh+top+1);
		for(int i=1;i<=top;i++)if(hsh[i]!=hsh[i-1])mp[hsh[i]]=++tot;
		for(int i=1;i<=n;i++)
		{
			hd[i]=mp[hd[i]];
			for(int j=0;j<son[i].size();j++)
				son[i][j]=mp[son[i][j]];
		}
		for(int i=1;i<=n;i++)
			for(int j=0;j<son[i].size();j++)
			{add(son[i][j],hd[i]);du[hd[i]]++;}
		puts(topsort()?"No":"Yes");
	}
	return 0;
}

rp++

posted @ 2019-11-13 06:12  HEOI-动动  阅读(187)  评论(0编辑  收藏  举报