hdoj 2647 Reward(逆向拓扑排序+队列)

Reward

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

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  
题意:有n个人,他们提出m个要求(就是x的奖励要比y高)。问你能否满足所有人要求,若能输出最少花费的钱,反之输出-1。

这道题不能用矩阵表示,因为1w*1w绝对超内存,分析数据,前一个a的钱要多于后一个b,
所以我们要把b作为出度,a为入度,如果不明白这个地方,
举例:b——>a——>c——>d ,b为888,钱数逐渐上升,如果反过来a为出度就不符合题意啦。。。
还有一个地方需要注意:
判断输出-1的情况不能只判断没有一个入度为0的点,
因为有可能在中间就出现矛盾了,如:a——>b——>c——>d——>c 有入度为0的点,但却要输出-1;

逆向拓扑排序

反向建边

根据每对限制,可确定拓扑序列,但此时的拓扑序列可能有多个(没有之间关系的点的顺序不定)。本题要求较小的点排到前面,则可确定序列。

(1)如果点a和点b有直接和简接的拓扑关系,那么a和b的先后顺序可有拓扑排序确定。

(2)如果点a和点b没有直接和简接的拓扑关系,那么a和b的先后顺序由a和b所能到达的点的确定。


<span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<queue>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define MAX 10010
int n,m;
int indegree[MAX];//入度
int head[MAX];
int reward[MAX];//奖金

struct node
{
	int to;
	int next;
}edge[2*MAX];

//priority_queue<int,vector<int>,greater<int> >q;//此处用优先队列 是错误的选择
queue<int>q;
int  topsort()
{
	int i;
	for(i=1;i<=n;i++)
	  if(indegree[i]==0)//将图中没有前驱的顶点(入度为0)的顶点加入队列
	   q.push(i);
	int sum=0,count=0,k=0;
	while(!q.empty())<span style="font-family: Arial, Helvetica, sans-serif;">//使用队列中的点更新indegree[]并生成拓扑排序序列</span>

	{
		//int v=q.top();
		int v=q.front();
		q.pop();
		sum+=reward[v];//将奖金加起来
		count++;//计算次数
		for(k=head[v];k!=-1;k=edge[k].next)//删除从顶点出发的全部有向边,更新indegree[]
		{
			indegree[edge[k].to]--;
			if(indegree[edge[k].to]==0)//如果indegree[i]==0说明新的没有前驱的顶点被找到,并加入到队列中
			{
				q.push(edge[k].to);
				reward[edge[k].to]=reward[v]+1;
			}
		}
	}
	if(count!=n)
	   sum=-1;
	   return sum;
}
int main()
{
  while(~scanf("%d%d",&n,&m))
  {
  	memset(head,-1,sizeof(head));//初始化
  	memset(indegree,0,sizeof(indegree));
  	for(int i=1;i<=n;i++)//题意说至少是888元,因此可以据此为基准
  	  reward[i]=888;
  	  int k=0;
  	  while(m--)
  	  {
  	  	int a,b;
  	  	scanf("%d%d",&a,&b);//建立反向拓扑排序
  	  	edge[k].to=a;//本来是将a当作尾部,但此处将其当作头部
  	  	edge[k].next=head[b];//将b当作尾部
  	  	head[b]=k++;
  	  	indegree[a]++;//入度从a看
	  }
	  int ans=topsort();
	  printf("%d\n",ans); 
  }
  return 0;
}</span>


    原文作者:拓扑排序
    原文地址: https://blog.csdn.net/lh__huahuan/article/details/47088601
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞