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

猜你喜欢

转载自www.cnblogs.com/Tony-Double-Sky/p/9495271.html
今日推荐