拓扑排序(1)--hdu2647(拓扑排序邻接表模板 应用判断是否存在环)

                                            Reward

                                                       Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)



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

题意:
老板要给很多员工发奖金, 但是部分员工有个虚伪心态, 认为自己的奖金必须比某些人高才心理平衡; 但是老板很人道, 想满足所有人的要求, 并且很吝啬,想花的钱最少
输入若干个关系
a b
a c
c b
意味着a 的工资必须比b的工资高 同时a 的工资比c高; c的工资比b高
当出现环的时候输出-1


这道题不能用矩阵表示,因为1w*1w绝对超内存,分析数据,前一个a的钱要多于后一个b,所以我们要把b作为出度,a为入度,如果不明白这个地方,举例:b——>a——>c——>d ,b为888,钱数逐渐上升,如果反过来a为出度就不符合题意啦。。。


还有一个地方需要注意:判断输出-1的情况不能只判断没有一个入度为0的点,因为有可能在中间就出现矛盾了,如:a——>b——>c——>d——>c 有入度为0的点,但却要输出-1;代码:
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
#define MAX 10005
int n,sum,ans;
int into[MAX],head[MAX],money[MAX];
struct Reward
{
    int to;
    int next;
} edge[2*MAX];
void topu()
{
    int i,j,l,v;
    queue<int>Q;
    for(i=1; i<=n; i++)
        if(into[i]==0)
            Q.push(i);//把入度为0的点压如队列
    while(!Q.empty())
    {
        v=Q.front();//调用首位元素
        sum+=money[v];
        Q.pop();//出队
        ans++; //用一个变量记录调用元素的总量,最后与n作比较
        for(l=head[v]; l!=-1; l=edge[l].next)//与队首元素v有关的都枚举一遍
        {
            if(--into[edge[l].to]==0)//如果入度-1为0,即为v的下一个元素
            {
                Q.push(edge[l].to);//将其压入队列
                money[edge[l].to]=money[v]+1;//保证后一个要比前一个多1
            }
        }

    }
}
int main()
{
    int m,a,b,tot;
    while(scanf("%d%d",&n,&m)!=EOF)
    {

        memset(head,-1,sizeof(head));
        memset(into,0,sizeof(into));
        for(int i=1; i<=n; i++)
            money[i]=888;//所有人一开始都为888
        tot=0;
        sum=0;
        ans=0;
        while(m--)
        {
            scanf("%d%d",&a,&b);//注意要逆过来,因为后一个b是基础的888,应当作为出度
            edge[tot].to=a;
            edge[tot].next=head[b];
            head[b]=tot++;
            into[a]++;//记录入度
        }
        topu();
        if(ans!=n)//有可能在中间出现矛盾,必须保证每个地方都不矛盾
            sum=-1;
        cout<<sum<<endl;

    }

}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值