Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 13744 Accepted Submission(s): 4410 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.
Input One line with two integers n and m ,stands for the number of works and the number of demands .(n<=10000,m<=20000)
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
Recommend yifenfei | We have carefully selected several similar problems for you: 1285 1811 2680 2112 2094 |
题目大意:老板要给N个员工发工资,要求每个人最少888块且要满足M个要求.比如1号员工的工资要比2号员工的工资多.老板准备满足所有要求且最终发的奖金总数要最少.如果可行输出总数,不可行输出-1.
思路:要注意对于任意奖金数(比如889或888)可能有多个员工获得同样的奖金.
将整个拓扑图分层,位于第0层的是那些可以获得888奖金的,位于第1层的是可以获得889奖金的,依次类推.最终的奖金总数就是888*N+ans(所有节点层数总和).
依然用的拓扑排序的方法,不过我们分解图的过程中只需要计算出每个节点所在的树层次即可.
建立拓扑图的时候,我们可以反向建立,也就是说那些拿钱少的,是前置,
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#define maxn 10010
using namespace std;
int n,m;
int ans;
struct Node
{
int in,dep; //入度及其点的深度
int head;
}node[maxn];
struct Edge
{
int to; //尾节点
int next; // 下一条边
}edge[maxn*2];;
void add_edge(int i,int u,int v)
{
edge[i]=(Edge){v,node[u].head};
node[u].head=i;
node[v].in++;
}
bool topo()
{
queue<int >Q;
ans=0;
int sum=0;
for(int i=1;i<=n;i++)
if(node[i].in==0) Q.push(i);
while(!Q.empty())
{
int u=Q.front();Q.pop();
sum++;
ans+=node[u].dep;
for(int e=node[u].head;e;e=edge[e].next) //模拟对于节点边的判断
{
int v=edge[e].to;
if(--node[v].in==0)
{
Q.push(v);
node[v].dep=node[u].dep+1;
}
}
}
return sum==n;
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
memset(node,0,sizeof(node));
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(i,v,u); //注意反向建图
}
printf("%d\n",topo()?888*n+ans:-1);
}
return 0;
}