UVA12167 Proving Equivalences

UVA12167 Proving Equivalences

题意翻译
题目描述 在数学中,我们常常需要完成若干命题的等价性证明。

例如:有4个命题a,b,c,d,要证明他们是等价的,我们需要证明a<=>b,然后b<=>c,最后c<=>d。注意每次证明是双向的,因此一共完成了6次推导。另一种证明方法是:证明a->b,然后b->c,接着c->d,最后d->a,只须4次证明。

现在你任务是证明 n 个命题全部等价,且你的朋友已经为你作出了m次推导(已知每次推导的内容),你至少还需做几次推导才能完成整个证明。

输入数据 有T(T<=100)组数据,每组数据第一行为两个整数n和m(1<=n<=20000, 1<=m<=50000),即命题数和已完成的推导个数(编号为1..n)。以下m行每行包含两个整数s1和s2(1<=s1,s2<=n,s1!=s2),表明已经证明了s1->s2。

输出数据 输出还需要做推导数的最小值。

感谢@hicc0305 提供的翻译


错误日志: 没有特判 \(numc = 1\) (即任意两点互通)时答案为 \(0\) 的情况


Solution

强联通分量搞成 \(DAG\) , 因为需要加边把图变为一个大强联通分量, 考虑出度和入度为 \(0\) 的点的数量, 这些点无法被到达或无法到达其他点, 输出计数的较大值即可满足所有点互达

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define cln(s, v) memset(s, v, sizeof(s))
typedef long long LL;
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 1000019,INF = 1e9 + 19;
int head[maxn],nume = 1;
struct Node{
    int v,dis,nxt;
    }E[maxn << 3];
void add(int u,int v,int dis){
    E[++nume].nxt = head[u];
    E[nume].v = v;
    E[nume].dis = dis;
    head[u] = nume;
    }
int DFN[maxn], LOW[maxn], INDEX;
int numc, col[maxn];
bool ins[maxn];
int S[maxn], top;
void Tarjan(int u){
	DFN[u] = LOW[u] = ++INDEX;
	S[++top] = u;ins[u] = 1;
	for(int i = head[u];i;i = E[i].nxt){
		int v = E[i].v;
		if(!DFN[v])Tarjan(v), LOW[u] = min(LOW[u], LOW[v]);
		else if(ins[v])LOW[u] = min(LOW[u], DFN[v]);
		}
	if(DFN[u] == LOW[u]){
		numc++;
		while(S[top + 1] != u){
			col[S[top]] = numc;
			ins[S[top--]] = 0;
			}
		}
	}
int ing[maxn], outg[maxn];
void init(){
	cln(head, 0), nume = 1;
	INDEX = 0, cln(DFN, 0), cln(LOW, 0);
	cln(col, 0), numc = 0;
	cln(ing, 0), cln(outg, 0);
	}
int T, num, nr;
int main(){
	T = RD();
	while(T--){
		init();
		num = RD();nr = RD();
		for(int i = 1;i <= nr;i++){
			int u = RD(), v = RD();
			add(u, v, 0);
			}
		for(int i = 1;i <= num;i++)if(!DFN[i])Tarjan(i);
		if(numc == 1){printf("0\n");continue;}
		for(int u = 1;u <= num;u++){
			for(int i = head[u];i;i = E[i].nxt){
				int v = E[i].v;
				if(col[u] != col[v]){
					ing[col[v]]++;
					outg[col[u]]++;
					}
				}
			}
		int in = 0, out = 0;
		for(int i = 1;i <= numc;i++){
			if(ing[i] == 0)in++;
			if(outg[i] == 0)out++;
			}
		printf("%d\n", max(in, out));
		}
	return 0;
	}
posted @ 2018-08-17 20:56  Tony_Double_Sky  阅读(102)  评论(0编辑  收藏  举报