【HDU】-5695-Gym Class(拓扑&贪心&STL)

12 篇文章 0 订阅
5 篇文章 0 订阅

 Gym Class
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

Description

众所周知,度度熊喜欢各类体育活动。 

今天,它终于当上了梦寐以求的体育课老师。第一次课上,它发现一个有趣的事情。在上课之前,所有同学要排成一列, 假设最开始每个人有一个唯一的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 的同学排在他(她)之前。你可以认为题目保证至少有一种排列方法是符合所有要求的。 

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;	
} 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值