📂图论
🔖题解
2025-02-15 15:52阅读: 7评论: 0推荐: 0

一本通【例4-13】奖金——拓扑序列

原题

题目描述

由于无敌的凡凡在2005年世界英俊帅气男总决选中胜出,Yali Company总经理Mr.Z心情好,决定给每位员工发奖金。公司决定以每个人本年在公司的贡献为标准来计算他们得到奖金的多少。
于是Mr.Z下令召开m方会谈。每位参加会谈的代表提出了自己的意见:“我认为员工a的奖金应该比b高!”Mr.Z决定要找出一种奖金方案,满足各位代表的意见,且同时使得总奖金数最少。每位员工奖金最少为100元。

输入

第一行两个整数n,m,表示员工总数和代表数;
以下m行,每行2个整数a,b,表示某个代表认为第a号员工奖金应该比第b号员工高。

输出

若无法找到合理方案,则输出“Poor Xed”;否则输出一个数表示最少总奖金。

思路

第i个领导认为ai比bi的奖金高,把领导当成边,ai>bi就是建立单向边,而没有被指也就是入度为0的便是钱最多的,这不就是拓扑序吗?本人考试还用的dfs,最开始还想打并查集

拓扑序模板

#include <bits/stdc++.h>

using namespace std;
const int INF = 0x3f3f3f3f;


//本代码功能:以bfs输出一个有向无环图DAG的拓扑序
const int N = 1010;
vector<int> edge[N];    //邻接表
int ind[N];             //入度数组
queue<int> q;          //队列

int n;          //n个结点
int m;          //m条边
int main() {
    //读入,建图
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        edge[x].push_back(y);
        ind[y]++;//维护入度
    }
    //入度为零的放入队列
    for (int i = 1; i <= n; i++) if (!ind[i]) q.push(i);

    //广度优先搜索DAG,就是拓扑排序的模板
    while (!q.empty()) {
        int x = q.front();
        q.pop();
        //输出拓扑序
        cout << x << " ";
        for (int i = 0; i < edge[x].size(); i++) { //遍历所有出边
            int y = edge[x][i];                    //目标结点
            //对接点入度-1,抹去这条入边
            ind[y]--;
            //如果入度为0,则入队列,准备处理它
            if (!ind[y]) q.push(y);
        }
    }
    return 0;
}

结合题干

在做题是我一直因为拓扑序输出的是从大到小而苦恼,终于才想起反向建边。还要记得判断环(其实数据里面没有环因为我没骗到分

上代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=10010;
vector<int> e[N];
int d[N],pri[N];//d[]存入度  pri[]存奖金 
signed main(){
    int n,m;
    cin>>n>>m;
    while(m--){
        int u,v;
		cin>>u>>v;
		e[v].push_back(u);//反向建边 
		++d[u];//记录入度(也就是有几个人比他大) 
    }
    queue<int> q;
    for(int i=1;i<=n;++i){
        if(d[i]==0) pri[i]=100,q.push(i);//入度为0的点代表他最小,所以果断入队并给出100元高额奖金(doge)    	
	}
    int cnt=0;//记录入队数(判断环,也就是不成立的条件)   
    while(!q.empty()){//注意:由于之前的u被弹出,所以下一次循环时下一行代码u读入的就是循环结束时加过1的新u,以达到记录奖金的,目的 
        int u=q.front();//记录最小奖金 
		++cnt;//入队人数++ 
		q.pop();//弹出 
		for(int v:e[u]){//遍历u(幸运儿)指向的每个点 
            --d[v];//度数--,因为幸运儿离开,少了一个人指他们 
			if(d[v]==0) {
				pri[v]=pri[u]+1,q.push(v);//找下一个幸运儿,奖金+1 
			} 
        }
    }
    if(cnt!=n){//入队数量与人数不符,故在图中形成了环,所以无解 
    	cout<<"Poor Xed";
	}else{  
        int sum=0;
        for(int i=1;i<=n;++i)
            sum+=pri[i];//记录总奖金数 
        cout<<sum;
    }
    return 0;
}

打个广告:欢迎参观我的博客谢谢

本文作者:ccgc718

本文链接:https://www.cnblogs.com/ccgc718/p/18717073

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ccgc718  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起