Reward
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8426 Accepted Submission(s): 2693
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.
then m lines ,each line contains two integers a and b ,stands for a's reward should be more than b's.
2 1 1 2 2 2 1 2 2 1
1777 -1
这道题一开始出现在我们训练的专题中是打算放弃的,因为学长说这道题要用到“拓扑排序”,对于这个拓扑排序我一无所知,后来学习了学长的代码加上网查了点资料就有点了解了。
先来说说这道题
题意 :
一位大老板要为他的员工发工资,但是这些员工有攀比心,即某个人要求他的工资比某个人高,但他们的老板是个好老板,他决定满足所有人的要求,并且最小工资是 888 。那么我们当然就能想到,在这个环境之下,老板支付最少的情况就是同一阶级的人们都发一样的工资并且从888开始,以后每一阶级只增加一块钱!
输入 :
第一行 两个数 n m ,表示有n位员工,有m条要求,接下来m行 每行 输入a b,表示 a的工资要比b高
做法:
那么我的做法是,用拓扑排序。拓扑排序就是指在一个“有向图”中每个点只会出现一次,并且那些点有出度和入度(例如 a -> b 那么a就是b的入度,b就是a的出度)那么按照题目输入把图画出来后,我们能找到一个点,它的出度为0,也就是说他没有指向的目标,根据题意也就是它是最低级要求,那么就把这个点放进队列里面。找到所有出度为0的点放进队列里。然后就循环你的队列,在里面从上面开始把里面的点拿出来,(ps:拓扑排序所用到的一个函数vector,它生成一个动态数组,在这个点的结构体里面,用来存这个点的上家,也就是这个点的入度)然后把这个点的工资算上后,把它的入度点的出度都减一,然后减过后如果出现了出度为0的点,也把它放进队列里,这样进行到底就可以了,那么如果这个图出现了环(就是 a -> b,b ->c,c->a)那么这种情况是无解的,输出-1
代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 40010
struct node{
vector <int> child; //生成动态数组用来储存 一个点的上家
int du,n;
}num[maxn];
queue<node>q; //创建一个队列
int main(){
int n,m,a,b,ans,total;
while(scanf("%d %d",&n,&m) != EOF){
while(!q.empty()) //清空队列
q.pop();
memset(num,0,sizeof(num));
for(int i = 0;i < m;i++){
scanf("%d %d",&a,&b);
num[b].child.push_back(a); //把 a 作为 b 的上家
num[a].du++; // 从 a 到 b 所以 a 出度加一
}
for(int i = 1;i <= n;i++){
if(num[i].du == 0){ //出度为 0的点就可以放进队列了,因为此时它是最低级
num[i].n = 0;
q.push(num[i]); //把这个出度为 0 的放进队列进行操作
}
}
ans = total = 0;
while(!q.empty()){
node p = q.front();
q.pop();
ans += p.n; // n用来表示这个点是第几批进队列的点
total++; //total 表示已经处理过的点的个数
for(int i = 0;i < p.child.size();i++){ // p.child.size()表示 该数组里的元素个数
num[p.child[i]].du--; // 处理这个点的时候,这个点的所有上家的出度要减一
if(num[p.child[i]].du == 0){ //处理完后如果这个点的出度为 0,那么它也可以放进队列进行操作了
num[p.child[i]].n = p.n + 1; // 下一批进队列的要比上一批出队列的等级高,所以 n + 1
q.push(num[p.child[i]]); // 把要操作的点放进队列
}
}
}
ans += n * 888; //因为题目说工资最少是888,所以除了已经加进去的多的工资,每个人都要把最小工资加上
if(total != n) // 如果total != n 表示里面成环了,不会出现出度为 0 的点了,无解
ans = -1;
printf("%d\n",ans);
}
}