分析:由题意可以知道根据贪心的思想ID越是大的人越应该放到前面,但是题目中又要求有的人必须站在另一个的前面,所以这个题目就是一个简单的拓扑排序了。
把所有人看做一个带权点。权值为ID值。然后如果读入一个A,B表示A不想B站在A的前面。那么就引一条从A到B的有向边。
那么bfs遍历。入队列要求是必须入度为0,出队列的时候出队列中ID值最大点。并且将这个点指向的所有点的入度减去1。遍历顺序即是排队的顺序。
代码:
#include<iostream>
#include<cstring>
#include<string>
#include <cstdio>
#include<cmath>
#include<queue>
#define INF 1700000000
using namespace std;
vector<int> e[100010];
int team[100010];
int top;
int n, m;
struct node
{
int data;
node(int d = 0){ data = d; }
friend bool operator<(node x, node y){
return x.data < y.data;
}
};
int ru[100010];
int chu[100010];
int visit[100010];
void BFS()
{
top = 0;
memset(visit, 0, sizeof(visit));
priority_queue<node> q;
for (int i = 1; i <= n; i++)
{
if (ru[i] == 0 )
{
visit[i] = 1;
q.push(node(i));
}
}
while (q.size())
{
int now = q.top().data;
team[top++] = now; //记录出队顺序
q.pop();
for (int i = 0; i < e[now].size(); i++)
{
ru[e[now][i]] --; //指向的节点入度减1
if (visit[e[now][i]] || ru[e[now][i]] > 0) continue; //如果该点已经走过或者入度不为0就跳过
visit[e[now][i]] = 1;
q.push(node(e[now][i]));
}
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> n >> m;
memset(ru, 0, sizeof(ru));
memset(chu, 0, sizeof(chu));
for (int i = 1; i <= n; i++) e[i].clear();
for (int i = 0; i < m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
chu[u] ++;
ru[v] ++;
e[u].push_back(v);
}
long long ans = 0;
BFS();
int Min = n;
for (int i = 0; i < top; i++)
{
if (team[i] < Min) Min = team[i];
ans += Min;
}
printf("%lld\n", ans);
}
return 0;
}