Description
众所周知,度度熊喜欢各类体育活动。
今天,它终于当上了梦寐以求的体育课老师。第一次课上,它发现一个有趣的事情。在上课之前,所有同学要排成一列, 假设最开始每个人有一个唯一的ID,从1到 N ,在排好队之后,每个同学会找出包括自己在内的前方所有同学的最小ID,作为自己评价这堂课的分数。麻烦的是,有一些同学不希望某个(些)同学排在他(她)前面,在满足这个前提的情况下,新晋体育课老师——度度熊,希望最后的排队结果可以使得所有同学的评价分数和最大。
今天,它终于当上了梦寐以求的体育课老师。第一次课上,它发现一个有趣的事情。在上课之前,所有同学要排成一列, 假设最开始每个人有一个唯一的ID,从1到 N ,在排好队之后,每个同学会找出包括自己在内的前方所有同学的最小ID,作为自己评价这堂课的分数。麻烦的是,有一些同学不希望某个(些)同学排在他(她)前面,在满足这个前提的情况下,新晋体育课老师——度度熊,希望最后的排队结果可以使得所有同学的评价分数和最大。
Input
第一行一个整数
T
,表示
T(1 \leq T \leq 30)
组数据。
对于每组数据,第一行输入两个整数 N 和 M (1 \leq N \leq 100000, 0 \leq M \leq 100000) ,分别表示总人数和某些同学的偏好。
接下来 M 行,每行两个整数 A 和 B(1 \leq A, B \leq N) ,表示ID为 A 的同学不希望ID为 B 的同学排在他(她)之前。你可以认为题目保证至少有一种排列方法是符合所有要求的。
对于每组数据,第一行输入两个整数 N 和 M (1 \leq N \leq 100000, 0 \leq M \leq 100000) ,分别表示总人数和某些同学的偏好。
接下来 M 行,每行两个整数 A 和 B(1 \leq A, B \leq N) ,表示ID为 A 的同学不希望ID为 B 的同学排在他(她)之前。你可以认为题目保证至少有一种排列方法是符合所有要求的。
Output
对于每组数据,输出最大分数 。
Sample Input
3 1 0 2 1 1 2 3 1 3 1
Sample Output
1 2 6
题解:从最优的解法考虑就是让大的尽可能排在前面,这样大的前面没有小的,最小的是自己,和才会大。
优先队列(从大到小排序),使没有约束的(入度为0)先进队列,再判断队列里的数(取出,放进数组)是否对其他数有约束,解除那个数的约束(入度变为0)后,这个数也进队列,以此类推......
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<functional>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
const int M=1e5+10;
vector<int> pos[M];
bool vis[M];
priority_queue<int ,vector<int> ,less<int> > q; //从大到小排序
int in[M];
int a[M];
int main()
{
int u;
scanf("%d",&u);
while(u--)
{
int n,m;
CLR(in,0);
CLR(vis,false);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
pos[i].clear(); //清空
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d %d",&x,&y);
pos[x].push_back(y); //建立关系
in[y]++; // y 入度++
}
for(int i=1;i<=n;i++)
{
if(!in[i])
{
q.push(i); //入度为 0 ,没有限制,进入队列,排在前面
vis[i]=true;
}
}
int ant=1;
while(!q.empty())
{
int pr=q.top();
q.pop();
a[ant++]=pr; //优先取出,考虑他的下属,而且他进数组
for(int i=0;i<pos[pr].size();i++)
{
in[pos[pr][i]]--;
if(!vis[pos[pr][i]]&&in[pos[pr][i]]==0) //只有入度-1=0时才进队列,因为此时说明它只有之前的一个限制了
{
q.push(pos[pr][i]);
vis[pos[pr][i]]=1; //标记,省的再判
}
}
}
int minn=1e5+10;
long long ans=0;
for(int i=1;i<=n;i++)
{
minn=min(minn,a[i]); //从大到小取,最大的前面没有,最小的数就是本身,并不断更新minn
ans+=minn;
}
printf("%lld\n",ans); //int会wa
}
return 0;
}