http://acm.hdu.edu.cn/showproblem.php?pid=2647
题意:
n个人和m个关系。m个关系中 a要比b工资多。问最少老板要发多少工资;
分析:
应用 拓扑排序 会产生不唯一的序列。需要在进行拓扑排序的时候做一些特殊的操作。当入度为0的集合中有多个点时,这些点是位于同一等级的。
//第一次用 拓扑排序写题,也是第一次用链式前向星建图。感觉不错。
//感觉在删边的时候复杂化了。
拓扑排序步骤操作:
1.维护一个入度为0的顶点的集合S:
2.每次从该集合中取出(没有特殊的取出规则,随机取出也行,使用队列/栈也行,下同)一个顶点,将该顶点放入保存结果的List中。
3.紧接着循环遍历由该顶点引出的所有边,从图中移除这条边,同时获取该边的另外一个顶点,如果该顶点的入度在减去本条边之后为0,那么也将这个顶点放到入度为0的集合中。然后继续从集合中取出一个顶点…………
当集合为空之后,检查图中是否还存在任何边,如果存在的话,说明图中至少存在一条环路。不存在的话则返回结果List,此List中的顺序就是对图进行拓扑排序的结果。//拓扑排序的结果是不唯一的,若要保证最小就在第二步取点的时候将点都sort一次
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 10000 + 100;
const int M = 20000 + 100;
const int INF = 0x3f3f3f3f;
struct Node //from
{
int next,to;
Node (){}
Node (int a,int b) : next(a),to(b){}
};
int head[N]; struct Node edge[M]; int nedge;
void add_edge(int a,int b)
{
edge[++nedge] = Node(head[a],b);
head[a] = nedge;
}// to 前向星建图
int node[N];
struct cost
{
int x;
int mon;
};
queue<cost> que;
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m))
{
LL ans = 0;
memset(node,0,sizeof(node));
memset(head,-1,sizeof(head));// head -> -1
nedge = -1; // 上同
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d %d",&y,&x);
add_edge(x,y);
node[y] ++;
}
struct cost cur;
cur.mon = 888;
for(int i=1;i<=n;i++)
if(node[i]==0) cur.x = i, que.push(cur);
while(!que.empty())
{
cur = que.front();
que.pop();
ans += cur.mon;
for(int i= head[cur.x];~i;i=edge[i].next)
{
int v = edge[i].to;
if(v==INF) continue;
node[v] --;
m--;
edge[i].to = INF;
if(node[v]==0)
{
struct cost now;
now .x = v;
now.mon = cur.mon +1;
que.push(now);
}
}
}
if(m) printf("-1\n");
else printf("%lld\n",ans);
}
return 0;
}