奖金
题目描述
由于公司在2013年的销售业务成绩优秀,公司总经理心情大好,决定给每位员工发奖金。公司决定以每个人本年在公司的贡献为标准来计算他们得到奖金的多少。于是总经理下令召开 m 方会谈。每位参加会谈的代表提出了自己的意见:“我认为员工 a 的奖金应该比 b 高!”。总经理决定要找出一种奖金方案,满足各位代表的意见,且同时使得总奖金数最少。每位员工奖金最少为100元。
输入格式
第一行两个整数 n 和 m,表示员工总数和代表数;
接下来有 m 行,每行 2 个整数 a 和 b,表示某个代表认为第 a 号员工奖金应该比第 b 号员工高。
输出格式
若无法找到合理方案,则输出“Poor Xed”;否则输出一个数表示最少总奖金。
样例数据 1
输入 [复制]
2 1
1 2
输出
201
备注
【数据规模】
80%的数据满足:n<=1000,m<=2000;
100%的数据满足:n<=10000,m<=20000。
算法分析:
如果把每个人当成点,则“我认为员工a的奖金应该比b高”就意味着点与点之间有先后关系,从b因一条线到a。这样就可以画出一个有向图。当能找到一个拓扑排序时就说明可以找到一种方案,但如果找不到一个拓扑排序,就说明这个有向图有环,找不到合适的方案。问题解决。
举个例子来看:
样例:
5 4
4 2
3 4
5 4
3 5
对应的图为:
拓扑排序的规则:入度为0的入队列,所有在每一个点入队列 时就可以确定他的钱数。即1,2入队列时他们是初始值100, 4入队列时,他的是2的钱数+1.依次类推。所以用数组mon[i]表示第i个人的奖金数则 :
mon[1]=mon[2]=100;
mon[4]=mon[2]+1;
mon[5]=mon[4]+1;
mon[3]=mon[5]+1;
代码为:
#include<iostream>
#include <cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int r[10005],m,n,money;
queue<int> q;//队列
//邻接表存储
struct edge{
int y,nex;
}e[20005];
int head[10005],mon[10005],num=0;
bool topsort() //拓扑排序
{
int tot,cs=0;
tot=0;//记录出队列的元素个数,判断是否有环
for(int i=1;i<=n;i++)
if(!r[i]) {
q.push(i);
mon[i]=100;//初始入度为0的点,钱数为200
money+=mon[i];
}
while(!q.empty()) //tot顶点个数
{
int x=q.front();
tot++;
q.pop();
for(int i=head[x];i;i=e[i].nex)
{
int yy=e[i].y;
r[yy]--;//把所有从x到达的边的入度都减去1;
if(!r[yy])//如果yy的入度为0,则说明从x到y的这条边是最后一条边,yy的钱数只需要比x多1元即可
{
q.push(yy);
mon[yy]=mon[x]+1;
money+=mon[yy];
}
}
}
if(tot==n) return true;
else return false;
}
void addedge(int x,int y)
{
num++;
e[num].y=y;
e[num].nex=head[x];
head[x]=num;
}
int main()
{
int a,b;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);//a比b高,则从b到a有条边
addedge(b,a);//b到a添加边
r[a]++; //统计入度
}
money=0;
if(topsort())cout<<money<<endl;
else cout<<"Poor Xed"<<endl;
return 0;
}
网上有很多题解,但方法与我不同,多多思考,总是会有意想不到的惊喜。