hdu2647 Reward (拓扑排序)

来源:互联网 发布:淘宝店标图片制作 编辑:程序博客网 时间:2024/04/27 17:50

Reward

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


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 11 22 21 22 1
 

Sample Output
1777-1
 

Author
dandelion
 

Source
曾是惊鸿照影来
 

想要发的薪水最少,就要让员工尽量只满足要求即可,不必多发。

我们可以大致想象出员工的薪水大概是一层一层分布的,即888一层,889一层,依此类推,每层有若干个员工,但一定不会为0。(想想为什么)

接下来,我们将员工依次从底层向上安排。

第一层的人肯定是那些没有要求的员工,因为他们对工资没有要求。

安排完第一层后,那些要求比第一层员工工资高的员工要求已经满足,我们可以将这些已经满足的要求删除掉,然后继续找当前没有工资要求的员工,放入第二层。

依此类推。

我们发现,上述思路和拓扑排序极为相似。于是反向建图后,稍加修改即可得到此题的解。

因为最少为888,上一层加1。


不能用矩阵保存,map[10005][10005]会超内存


#include<cstring>#include<queue>#include<cstdio>using namespace std;#define MAX 10005int n, sum,num, ans;int indegree[MAX], head[MAX],money[MAX];struct Reward{    int to;    int next;} edge[2 * MAX];void addEdge(int a, int b){    edge[num].to=b;    edge[num].next=head[a];        //上一条以u为起点的边的编号    head[a]=num++;                 //当前以u为起点的边的位置    indegree[b]++;                 //记录入度}   void topu(){    int i,j,u;    queue<int>q;    for (i=1;i<=n;i++)        if (indegree[i] == 0)            q.push(i);    while (!q.empty())    {        u=q.front();         sum+=money[u];        q.pop();        ans++;         for (i=head[u];i!=-1;i=edge[i].next) //与队首元素v有关的都枚举一遍,循环遍历        {        int k=edge[i].to;        indegree[k]--;            if (indegree[k]==0)             {                q.push(k);                money[k]=money[u]+1;                             }        }    }}int main(){    int m, a, b;    while (scanf("%d%d", &n, &m) != EOF)    {    num=0;        memset(head,-1,sizeof(head));        memset(indegree,0,sizeof(indegree));        memset(money,0,sizeof(money));           //设钱数都为0,入度即为多出的钱数             sum=ans=0;        for (int i=0;i<m;i++)        {            scanf("%d%d",&b,&a);            addEdge(a, b);        }        topu();        if (ans!=n) //当有不符合时,如1 2和2 1同时出现,入度都不为0,也就小于n             printf("-1\n");        else printf("%d\n",sum+n*888);          //再加上必须发的钱数     }    return 0;}



0 0
原创粉丝点击