传送门:Reward
题目大意是,boss 发工资,每个人都有一个最低工资,而某些员工比如 a 有攀比之心,要求工资必须比其他某个员工比如 b 高,给定若干如 a b 这样的序列,问 boss 最少需要发多少工资。
这就很容易联想到拓扑排序,只不过还需要算出每一层级的点的数量。由于在拓扑排序中,并不一定每个点两两之间都能够有着明确的先后次序,但有些点能够有共同的上级或下级,那么这些点(一个点其实也可以)就能够构成一个层级(以上均为瞎编的词语,明白意思就好,,)。或者说,这些点的集合作为一个整体在图中是有序的,而集合内的点是无法排出次序的。
于是,题目可以转化为:对于一个图,进行拓扑排序,从后到前每个层级的权值依次+1(工资最少导向),计算每个层级的点数乘以该层级的权重的和。
但是,这存在一个问题。如果按照 a b 即 a 与 b 之间连接一条从 a 指向 b 的有向路径,那么进行拓扑排序时就会发现,排在前面的也就是入度为 0 的点(假如是 a),是处于一个无法快速确定它的层级权值的位置。因为 a 要比 b 高,b 可能就要比 c 高,可能一直要到 z 这样老实人才不攀比,但这一切对于刚出队的 a 来说是未知的,也就难以立即确定 a 所在的层级的权重。
为了解决这个问题,我们可以反过来想,把 a b 视为 b 要比 a 低,也就是说,在 a 与 b 之间连接一条从 b 指向 a 的有向路径。那么,这样建图进行拓扑排序,首先出队的就是要求最低的点,而我们已知最低工资的大小,就可以立即确定它的权重了。
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e4+4;
int n, m;
vector<int> g[maxn];
int indeg[maxn];
int t[maxn];
void init()
{
for(int i = 0; i < maxn; ++i)
g[i].clear(), indeg[i] = t[i] = 0;
}
void read()
{
int u, v;
for(int i = 0; i < m; ++i)
{
cin >> u >> v;
g[v].push_back(u);
++indeg[u];
}
}
bool topoSort()
{
queue<int> q;
for(int i = 1; i <= n; ++i)
if(!indeg[i])
{
q.push(i);
t[i] = 0;
}
int cnt = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
++cnt;
for(int i = 0; i < g[u].size(); ++i)
{
int v = g[u][i];
if(!(--indeg[v]))
{
q.push(v);
t[v] = t[u]+1;
}
}
}
if(cnt < n)
return 0;
return 1;
}
void solve()
{
int ans = 0;
if(topoSort())
{
for(int i = 1; i <= n; ++i)
ans += 888+t[i];
cout << ans << endl;
}
else
cout << -1 << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
while(cin >> n >> m && n)
{
init();
read();
solve();
}
return 0;
}