HDU 2647 Reward

 Reward
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

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

加钱的时候顺序正好反着,可以在加边的时候就倒着加,从而加钱正着加;

两种方法:

第一种好理解;

代码1;

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
int num;//总边数; 
int head[10010];
int in[10010];
int mon[10010];//用来存储标号为i的人应该得到的钱数; 
struct node
{
	int to,next;
}a[20010];//数值较大用邻接表; 
void init()
{
	memset(in,0,sizeof(in));
	num=0;
	memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
	a[num].to=v;
	a[num].next=head[u];
	head[u]=num++;
	in[v]++;
}
int topo(int n)
{
	queue<int>q;
	int ans=0,sum=0;
	while(!q.empty())
	q.pop();
	for(int j=1;j<=n;j++)
	{
		if(in[j]==0)
		{
			q.push(j);//先把入度为0的点压入队列; 
			mon[j]=888;//前几个入度为0的点工资最少为888,用数组存起来;		
		}
	}
	while(!q.empty())
	{
		int t=q.front();
		q.pop();
		in[t]=-1;
		sum+=mon[t];//累加从队列中拿出的元素的钱数; 
		ans++;
		for(int i=head[t];i!=-1;i=a[i].next)
		{
			int b=a[i].to;
			in[b]--;//删边,即入度减一; 
			if(in[b]==0)
			{
				q.push(b);
				mon[b]=mon[t]+1;//每次在原有基础上加1; 
			}
		}
	}
	if(ans==n)//ans用来记录序列的点的个数,如果排序的点少于n那么信息不足或有冲突; 
	  printf("%d\n",sum);
	else
	  printf("-1\n");
}
int main()
{
	int n,m,a,b;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		init();
		for(int i=0;i<m;i++)
		{
			scanf("%d%d",&a,&b);
			add(b,a);
		}
		topo(n);
	}
	return 0;
}

代码2:

#include <iostream>  
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <math.h>  
#include <ctype.h>  
#include <queue>  
#include <map>  
#include <algorithm>  
using namespace std;  
int d[11000], head[11000], n, cnt, a[11000];  
struct node  
{  
    int u, v, w;  
    int next;  
}edge[22000];  
void add(int u, int v, int w)  
{  
    edge[cnt].v=v;  
    edge[cnt].w=w;  
    edge[cnt].next=head[u];  
    head[u]=cnt++;  
}  
void tops()  
{  
    int i, j, x, ss=888, ans=0, s=0, flag=0;//ss表示当前层数要加的钱数;ans表示总钱数;s表示当前选的总人数  
    while(1)  
    {  
        x=0;  
        for(j=1;j<=n;j++)  
        {  
            if(d[j]==0)  
            {  
                a[x++]=j;//记录此层选的人  
                d[j]--;  
                s++;  
            }  
        }  
        ans+=x*ss;  
        if(x==0&&s<n)  
        {  
            flag=1;//说明出现环,则不能满足要求  
            break;  
        }  
        if(x==0)  
            break;  
        for(i=0;i<x;i++)//将与该层所有人相连的均降度  
        {  
            for(j=head[a[i]];j!=-1;j=edge[j].next)  
            {  
                if(edge[j].w==1)  
                {  
                    edge[j].w--;  
                    d[edge[j].v]--;  
                }  
            }  
        }  
        ss++;//层数递增  
    }  
    if(flag)  
        printf("-1\n");  
    else  
        printf("%d\n",ans);  
}  
int main()  
{  
    int m, a, b;  
    while(scanf("%d%d",&n,&m)!=EOF)  
    {  
        memset(d,0,sizeof(d));  
        memset(head,-1,sizeof(head));  
        cnt=0;  
        while(m--)  
        {  
            scanf("%d%d",&a,&b);  
            add(b,a,1);  
            d[a]++;  
        }  
        tops();  
    }  
    return 0;  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值