1. 程式人生 > >Reward(拓撲排序)(含測試資料)

Reward(拓撲排序)(含測試資料)

Reward

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6725    Accepted Submission(s): 2081


Problem Description Dandelion's uncle is a boss of a factory. As the spring festival is coming , he wants to distribute rewards to his workers. Now he has a trouble about how to distribute the rewards.
The workers will compare their rewards ,and some one may have demands of the distributing of rewards ,just like a's reward should more than b's.Dandelion's unclue wants to fulfill all the demands, of course ,he wants to use the least money.Every work's reward will be at least 888 , because it's a lucky number.
Input One line with two integers n and m ,stands for the number of works and the number of demands .(n<=10000,m<=20000)
then m lines ,each line contains two integers a and b ,stands for a's reward should be more than b's.
Output For every case ,print the least money dandelion 's uncle needs to distribute .If it's impossible to fulfill all the works' demands ,print -1.
Sample Input 2 1 1 2 2 2 1 2 2 1
Sample Output 1777 -1
Author dandelion
Source

剛開始還以為是帶權並查集,迅速的敲完,然後就WA了。

後來測試了一組這樣的資料: 4 4 1 2 2 3 1 4 3 4

發現出問題了,後來才開始學習拓撲排序。

這道題要注意圖應該是有向圖,從誰出發到誰應該處理好,弄不好就懵了。

要是找不出bug的情況,不如試試以下型別的資料:

①普通題目中的資料(廢話)

②有獨立點的資料:3 1 1 2  ————  2665

③有環的資料(一種是無解的環,一種是有解的環):3 3 1 2 2 3 3 1 ———— -1 

4 4 1 2 2 3 1 4 3 4 ———— 3558

程式碼如下:

#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
	int from,to;		//表示方向 
}data[20022];

int n,m;
long long ans;
//int cost[10022];		//該點花費的錢數(為了計算下一個入度為0的節點) (好像這個多餘了)
int used[10022];		//是否遍歷過 
int in[10022];
int ach = 0;		//已完成的節點數 
bool flag;

void init()
{
	for (int i = 1 ; i <= n ; i++)
	{
		in[i] = 0;
		used[i] = 0;
	}
	ans = 0;
	flag = true;
}

void topo()
{
	queue<int>q;
	ach = 0;		//已完成的節點數 
	int s = 0;		//花費,每進行一輪花費加1(很樸素的方法,但是有效)
	while (1)
	{
		int k = 0;
		for (int i = 1 ; i <= n ; i++)
		{
			if (!used[i] && in[i] == 0)
			{
				q.push(i);
				k = 1;
				ans += s;
				ach++;
				used[i] = 1;
			}
		}
		if (k == 0)
			break;		//說明已經沒有入度為0的點了
		while (!q.empty())
		{
			int tt = q.front();
			q.pop();
			for (int i = 1 ; i <= m ; i++)
			{
				if (data[i].from == tt && used[data[i].to] == 0)
					in[data[i].to]--;		//把邊減掉 
			}
		}
		s++;
	}
}

int main()
{
	while (~scanf ("%d %d",&n,&m))
	{
		init();		//程式碼太亂,初始化忘了 = = 
		for (int i = 1 ; i <= m ; i++)
		{
			int t1,t2;
			scanf ("%d %d",&t1,&t2);		//這裡注意需要反向,應該是t2指向t1
			data[i].from = t2;
			data[i].to = t1;
			in[t1]++;		//表示入度 
		}
		topo();
		if (ach != n)
			printf ("-1\n");
		else
		{
			ans += n * 888;
			printf ("%lld\n",ans);
		}
	}
	return 0;
}