这道题题意很简单,老板给员工发福利,有些员工要求自己的福利必须比某个人高,老板希望在满足所有人的要求下,总花费最小。
拓扑排序分层,反向建表,正向也可以,只不过计算稍微麻烦些,但更接近题意。
这道题我还是卡了一会的,一开始用下标模拟堆栈的方法wa了好多次,后来试着调用stl的栈,接着wa,才发现是自己的分层策略和栈的性质不相容。
我的分层策略是,若有个点,在删去一个边之后入度变为0,则这个点的层数为刚刚删掉的那条边的起点的层数加1。
使用这种策略加上用栈会在处理一些特殊情况是发生错误。后来改为用队列才AC。
#include <iostream>
#include <vector>
#include <queue>
#include <stdio.h>
#include <memory.h>
using namespace std;
int counter[10005];
int Rank[10005];
int N,M;
vector<vector<int> > v;
bool TopoOrder()
{
queue<int> S;
int top=-1;
//下表模拟堆栈
for(int i=1;i<=N;i++)
{
if(counter[i]==0)
{
Rank[i]=0;
S.push(i);
}
}
//弹栈顶操作一共要进行N次,每次拿出一个顶点,删去它所连接的边,共有N个顶点所以要做N次
for(int i=0;i<N;i++)
{
if(S.empty())
return false;
else
{
int j=S.front();
S.pop();
for(int k=0;k<v[j].size();k++)
{
if(--counter[v[j][k]]==0)
{
S.push(v[j][k]);
Rank[v[j][k]]=Rank[j]+1;
}
}
}
}
return true;
}
void output()
{
long long ans=0;
for(int i=1;i<=N;i++)
{
ans+=Rank[i];
}
ans+=N*888;
cout<<ans<<endl;
}
int main()
{
int a,b;
while(~scanf("%d%d",&N,&M))
{
memset(counter,0,sizeof(counter));
v.clear();
v.resize(N+1);
for(int i=0;i<M;i++)
{
scanf("%d%d",&a,&b);
v[b].push_back(a);
counter[a]++;
}
if(!TopoOrder())
{
cout<<-1<<endl;
}
else
{
output();
}
}
return 0;
}
原文:http://www.cnblogs.com/modengdubai/p/4730877.html