HDU 2647 Reward (拓扑排序 + 链式前向星 )

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值