HDU2647 Reward(拓扑排序)

题目:

Reward

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


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
 

Recommend
yifenfei   |   We have carefully selected several similar problems for you:   1285  3342  1811  2680  2112 
 

Statistic |  Submit |  Discuss |  Note
思路:

又是一道拓扑排序的题,在这因为要发奖金而且前面人的奖金大于后面人的奖金,这时候我们需要反向建边,最后判环,有环的时候输出-1,利用path来存储比888大的多少的数,最后算出sum+888*n就好了

关于反向建边的原因:

分析,根据题意可以得出一个拓扑的关系,比如 一组数据:

4 4

1 2

1 3

2 4

3 4

那么有如图关系:(位于上层的要求比下层的高)

 由图可以知道,我们需要给1号890,2、3号889,4号888元,但是我们在拓扑排序的时候总是从入度为0的点 (从图中也就是1号) 开始,如果这样那么我们怎么知道 入度为 0 的点是在第几层呢?那么同样也不好计算总共的奖金数量。

在这里我用的是反向建边,那么建立之后 对于上案例如图:

如此的时候,我们在拓扑排序的时候第一次找到的点就是没有要求的工人,那么奖励就直接加888,再考虑这一层之后让基本奖励 + 1 ,再拓扑排序便可以了

来自: http://blog.csdn.net/zyy173533832/article/details/11483505

代码:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <string>
#include <set>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define mod 1000007
#define N 20100
#define M 100000+50
#define ll long long
using namespace std;
int n,m,len,k=0;
int first[N],vis[N],path[N];
struct node
{
	int u,v,next;
}G[N];
void add_edge(int u,int v)
{
	G[len].v=v;
	G[len].next=first[u];
	first[u]=len++;
}
void toposort()
{
	mem(path,0);
	stack<int>s;
	for(int i=1;i<=n;i++)
		if(!vis[i])
			s.push(i);
	while(!s.empty())
	{
		int u=s.top();
		s.pop();
		for(int i=first[u];~i;i=G[i].next)
		{
			int v=G[i].v;
			path[v]=max(path[v],path[u]+1);
			vis[v]--;
			if(!vis[v])
				s.push(v);
		}
	}

}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		len=1;
		mem(first,-1);
		mem(vis,0);
		int x,y;
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d",&x,&y);
			add_edge(y,x);
			vis[x]++;
		}
		toposort();
		int sum=0,flag=0;
		for(int i=1;i<=n;i++)
		{
			if(vis[i])
			{
				flag=1;
				break;
			}
			sum+=path[i];
		}
		if(flag)puts("-1");
		else printf("%d\n",sum+888*n);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值