HDU 5695 Gym Class && 百度之星 初赛 1006

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5695

本文链接:http://www.cnblogs.com/Ash-ly/p/5515234.html

题意:

  第 一次上课之前,所有同学要排成一列,假设最开始每个人有一个唯一的ID,从1到N在排好队之后,每个同学会找出包括自己在内的前方所有同学的最小ID,作 为自己评价这堂课的分数.麻烦的是,有一些同学不希望某个(些)同学排在他(她)前面,在满足这个前提的情况下,新晋体育课老师——度度熊,希望最后的排 队结果可以使得所有同学的评价分数和最大.

  第一行输入T,表示有T组数据.对于每组数据的第一行有两个数字N和M,代表总人数和某些同学的偏好,接下来M行,有两个数字A和B表示A不想让B站在他的前面.对于每组输入输出最大分数.

思路:

  如果A不想让B在他的前面,那么就可以认为A到B有一条有向边,那么就可以利用拓扑序列来做这道题了,但是要想每次首先访问到的是能访问到的中的最大值,那么可以把入度为零的所有点压入优先队列中,使得每次新的拓展节点是能拓展的种的最大值.

代码:

 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <algorithm>
 7 #include <queue>
 8 #include <stack>
 9 #include <vector>
10 using namespace std;
11 typedef long long LL;
12 const int MAXN = 100000;
13 vector<int> map[MAXN + 7];//图
14 int inder[MAXN + 7];//入度
15 
16 int main(){
17     //freopen("input.txt", "r", stdin);
18     int T;
19     scanf("%d", &T);
20     while(T--){
21         int n, m;
22         scanf("%d%d", &n, &m);
23         for(int i = 1; i <= n; i++)map[i].clear();
24         memset(inder, 0, sizeof(inder));
25         for(int i = 1; i <= m; i++){
26             int u, v;
27             scanf("%d%d", &u, &v);
28             map[u].push_back(v); // u 到 v 有一条有向边
29             inder[v]++;
30         }
31         priority_queue<int> Qu;
32         for(int i = 1; i <= n; i++) if(!inder[i]) Qu.push(i);//刚开始所有入度为0的点进队
33         LL ans = 0;
34         int minu = n + 1;
35         while(!Qu.empty()){
36             int head = Qu.top(); //获得下一个待扩展节点,一定是当前可扩展节点中最大的
37             Qu.pop();
38             minu = min(minu, head);//每个人的分数等于他以及他之前的人的编号的最小值
39             ans +=(LL) minu;
40             for(int i = 0; i < map[head].size(); i++)
41                 if( !(--inder[map[head][i]]) )//每访问一个点,就把从这个点出发的有向边删除,删除后出现新的入度为0的点,则进队
42                     Qu.push(map[head][i]);
43         }
44         printf("%lld
", ans);
45     }
46     return 0;
47 }
原文地址:https://www.cnblogs.com/Ash-ly/p/5515234.html