这道题题意很简单,老板给员工发福利,有些员工要求自己的福利必须比某个人高,老板希望在满足所有人的要求下,总花费最小。
拓扑排序分层,反向建表,正向也可以,只不过计算稍微麻烦些,但更接近题意。
这道题我还是卡了一会的,一开始用下标模拟堆栈的方法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; }
时间: 2024-10-10 07:02:07