la 4287 Proving Equivalences

题目:


大意:

比如如果存在关系A-->B,B-->C,C-->D,D-->A,就可以说ABCD四个量相等。

现在有n个,m个形如X-->Y的关系,求最少还需要添加几个这样的关系,使得n个相等。

(前面讲的一堆讲矩阵的话和本题无关)


思路:

对于每一个X-->Y的条件在X和Y之间连一条有向边。

可以从题目中看出,当且仅当n个点在同一个强连通块中时,n个量相等。

所以问题就转化成了在图中最少需要添加几条有向边使得全图强连通,根据强连通图的定义,这张图中一定不存在入度或出度为0的点。

由于强连通分量中的点入度和出度一定不为0,所以先用tarjan缩点,此时图变成了有向无环图。

这时要把所有出度为0的点上加一条出边,把所有入度为0的点上加一条入边,最小的情况就是尽量从出度为0的点引一条有向边到入度为0的点。

所以最后的结果就是入度为0的点和出度为0的点的数量的最大值。


注意:

1、由于n的范围是20000,所以不能用二维数组。

2、图中仅有一个强连通分量时,要特判。


代码:

#include<bits/stdc++.h>
using namespace std;

#define maxn 20000
#define maxm 50000

int n,m;

vector<int> a[maxn+5];

int pre[maxn+5],low[maxn+5];
int clk;

int scc[maxn+5];
int cnt;

stack<int> s;

int in0[maxn+5],out0[maxn+5];

void init() {
	for(int i=1; i<=maxn; i++) a[i].clear();
	memset(pre,0,sizeof(pre));
	memset(scc,0,sizeof(scc));
	clk=cnt=0;
	stack<int> emp;
	s=emp;
}

void readin() {
	scanf("%d%d",&n,&m);
	for(int i=1; i<=m; i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		a[x].push_back(y);
	}
}

void tj(int u) {
	pre[u]=low[u]=++clk;
	s.push(u);

	for(int i=0; i<a[u].size(); i++) {
		int v=a[u][i];
		if(!pre[v]) {
			tj(v);
			low[u]=min(low[v],low[u]);
		} else if(!scc[v]) {
			low[u]=min(pre[v],low[u]);
		}
	}

	if(low[u]==pre[u]) {
		int x;
		cnt++;
		do {
			x=s.top(),s.pop();
			scc[x]=cnt;
		} while(x!=u);
	}
}

void print() {
	for(int i=1; i<=cnt; i++) in0[i]=out0[i]=1;
	for(int i=1; i<=n; i++ ) {
		for(int j=0; j<a[i].size(); j++) {
			int u=scc[i],v=scc[a[i][j]];
			if(u!=v) in0[v]=0,out0[u]=0;
		}
	}
	int s1=0,s2=0;
	for(int i=1; i<=cnt; i++) {
		if(in0[i]) s1++;
		if(out0[i]) s2++;
	}
	if(cnt==1) printf("0\n");
	else printf("%d\n",max(s1,s2));
}

int main() {
	int T;
	scanf("%d",&T);

	while(T--) {
		init();
		readin();
		for(int i=1; i<=n; i++) if(!pre[i]) tj(i);
		print();
	}

	return 0;
}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值