洛谷P2881 [USACO07MAR]排名的牛Ranking the Cows

版权声明:我这么弱的蒟蒻,虽然博文不是很好,但也请标明转发地址喵! https://blog.csdn.net/ACerAndAKer/article/details/82781984

拓扑排序–>传递闭包

我们要知道所有牛的排名,就需要知道所有牛的相对排名,所以一共是n*(n-1)/2对,但是会有这样一些条件不需要知道:1>2,2>3,所以1>3所以第三对条件是不需要再找到一遍的,所以我们只需要找出这些不需要找的,用总数减去m再减去这些不需要的,就是最后结果
怎么求这些条件呢?不难发现,这玩意符合传递闭包,不存在环,所以我们可以反向建图,反向更新条件关系,然后最后统计答案就好了
例子
原顺序是1->2 1->3 2->4 3->5
那么反向建图之后依次向上更新,就可以得到每个点都能到达哪些点了

代码

//By AcerMo
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=10050;
int n,m;
int in[M],f[M/10][M/10];
int to[M],nxt[M],head[M],cnt;
inline int read()
{
	int x=0;char ch=getchar();
	while (ch>'9'||ch<'0') ch=getchar();
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x;
} 
inline void add(int x,int y)
{
	to[++cnt]=y;in[y]++;nxt[cnt]=head[x];head[x]=cnt;
	return ;
}
inline void tops()
{
	queue<int>q;
	for (int i=1;i<=n;i++) 
	if (!in[i]) q.push(i);
	while (q.size())
	{
		int u=q.front();q.pop();
		for (int i=head[u];i;i=nxt[i])
		{
			in[to[i]]--;f[to[i]][u]|=1;
			for (int k=1;k<=n;k++)
			f[to[i]][k]|=f[u][k];
			if (!in[to[i]]) q.push(to[i]);
		}
	}
	return ;
}
signed main()
{
	n=read();m=read();int x,y;
	for (int i=1;i<=m;i++)
	x=read(),y=read(),add(y,x);
	tops();int ans=(n-1)*n/2;
	for (int i=1;i<=n;i++)
	for (int k=1;k<=n;k++)
	ans-=f[i][k];
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ACerAndAKer/article/details/82781984