1. 程式人生 > >CODEVS P2833 奇怪的夢境

CODEVS P2833 奇怪的夢境

2833 奇怪的夢境

時間限制: 1 s 空間限制: 128000 KB 題目等級 : 黃金 Gold 題目描述 Description

Aiden陷入了一個奇怪的夢境:他被困在一個小房子中,牆上有很多按鈕,還有一個螢幕,上面顯示了一些資訊。螢幕上說,要將所有按鈕都按下才能出去,而又給出了一些資訊,說明了某個按鈕只能在另一個按鈕按下之後才能按下,而沒有被提及的按鈕則可以在任何時候按下。可是Aiden發現螢幕上所給資訊似乎有矛盾,請你來幫忙判斷。

輸入描述 Input Description

第一行,兩個數N,M,表示有編號為1...N這N個按鈕,螢幕上有M條資訊。

接下來的M行,每行兩個數ai,bi,表示bi按鈕要在ai之後按下。所給資訊可能有重複,保證ai≠bi。

輸出描述 Output Description

若按鈕能全部按下,則輸出“o(∩_∩)o”。

若不能,第一行輸出“T_T”,第二行輸出因資訊有矛盾而無法確認按下順序的按鈕的個數。輸出不包括引號。

樣例輸入 Sample Input

3 3

1 2

2 3

3 2

樣例輸出 Sample Output

T_T

2

資料範圍及提示 Data Size & Hint

對於30%的資料,保證0<N≤100。

對於50%的資料,保證0<N≤2000。

對於70%的資料,保證0<N≤5000。

對於100%的資料,保證0<N≤10000,0<M≤2.5N。



隨便找了一道純拓撲排序的題練了一下,感覺就是個模板題,非常水,畢竟難度等級只有這麼低。

看懂題目的意思發現其實就是ai到bi建一條有向邊,建完邊之後跑一邊拓撲排序,最後判斷是否所有點都能刪了。

如果有環,就表明不能打成目標,直接輸出總點數-已刪點數就行了。

至於拓撲排序的方法到處都有,我就不作解釋了。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=100001;
struct edge
{
	int node,next,w;
}h[MAXN];//這個資料要用鄰接表來存
int Head[MAXN],Dg[MAXN],stack[MAXN];//這裡我用的棧,感覺比較順手,其實都無所謂就是順序不一樣。
int n,m,tot,top=0,sum=0;
void add(int u,int v)//鄰接表加邊
{
	h[++tot].next=Head[u];
	h[tot].node=v;
	Head[u]=tot;
}
void push(int x)
{
	stack[++top]=x;
}
int pop()
{
	return stack[top--];
}//棧的兩個操作
void TPsort()//拓撲排序
{
	for(int i=1;i<=n;i++)
	if(!Dg[i])
	push(i);
	int v;
	while(top)
	{
		int x=pop();
		sum++;
		for(int i=Head[x];i;i=h[i].next)
		{
			v=h[i].node;
			if(Dg[v])
				Dg[v]--;
			if(!Dg[v])
			push(v);
		}
	}
	if(sum==n)
	cout<<"o(∩_∩)o";
	else
	cout<<"T_T"<<endl<<n-sum;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int x,y;
		cin>>x>>y;
		add(x,y);
		Dg[y]++;
	}
	TPsort();
	return 0;
}