题意:有多个命题,需要证明他们可以互相推出,现在已经有一些证明关系即 A 可以证明 B,问至少还需要多少证明关系。

首先,如果某几个命题证明关系可以成环,那么这些命题必然可以相互证明,只要沿着环的边走就能到达其他命题,所以首先是需要强连通缩点,之后对于一个无环图,我们发现如果一个强连通分量它无出度,那么它就不能证明其他任何命题,如果它无入度,那么它就不能由任何命题证明,那么我们就需要消除这些入度或出度为0的点,其实只需要将入度为 0 的点建边指向出度为 0 的点,然后剩下多余的,入度为 0 则随意向其他点出边,出度为 0 则随意让其他点向它建边,因此所需要建的边数就是入度为 0 点数和出度为 0 点数的最大值。如果一开始图就只剩一个强连通分量,那么虽然它的入度出度都为 0 ,但已经不需要加边。

UVALive4287、hdu2767

 #include<stdio.h>
#include<string.h>
#include<stack>
#include<queue>
using namespace std; const int maxn=2e4+;
const int maxm=5e4+; int head[maxn],point[maxm],nxt[maxm],size;
int n,t,scccnt;
int stx[maxn],low[maxn],scc[maxn],id[maxn],od[maxn],numi,numo;
stack<int>S; int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;} void init(){
memset(head,-,sizeof(head));
size=;
} void add(int a,int b){
point[size]=b;
nxt[size]=head[a];
head[a]=size++;
} void dfs(int s){
stx[s]=low[s]=++t;
S.push(s);
for(int i=head[s];~i;i=nxt[i]){
int j=point[i];
if(!stx[j]){
dfs(j);
low[s]=min(low[s],low[j]);
}
else if(!scc[j]){
low[s]=min(low[s],stx[j]);
}
}
if(low[s]==stx[s]){
scccnt++;
while(){
int u=S.top();
S.pop();
scc[u]=scccnt;
if(s==u)break;
}
}
} void setscc(){
memset(stx,,sizeof(stx));
memset(scc,,sizeof(scc));
memset(id,,sizeof(id));
memset(od,,sizeof(od));
numi=numo=t=scccnt=;
for(int i=;i<=n;++i)if(!stx[i])dfs(i);
if(scccnt!=){
for(int i=;i<=n;++i){
for(int j=head[i];~j;j=nxt[j]){
int k=point[j];
if(scc[i]!=scc[k]){
id[scc[i]]++;
od[scc[k]]++;
if(id[scc[i]]==)numi++;
if(od[scc[k]]==)numo++;
}
}
}
numi=scccnt-numi;
numo=scccnt-numo;
}
} int main(){
int T;
scanf("%d",&T);
while(T--){
int m;
scanf("%d%d",&n,&m);
init();
while(m--){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
setscc();
printf("%d\n",max(numi,numo));
}
return ;
}

hdu3836

恩,就是改下输入

 #include<stdio.h>
#include<string.h>
#include<stack>
#include<queue>
using namespace std; const int maxn=2e4+;
const int maxm=5e4+; int head[maxn],point[maxm],nxt[maxm],size;
int n,t,scccnt;
int stx[maxn],low[maxn],scc[maxn],id[maxn],od[maxn],numi,numo;
stack<int>S; int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;} void init(){
memset(head,-,sizeof(head));
size=;
} void add(int a,int b){
point[size]=b;
nxt[size]=head[a];
head[a]=size++;
} void dfs(int s){
stx[s]=low[s]=++t;
S.push(s);
for(int i=head[s];~i;i=nxt[i]){
int j=point[i];
if(!stx[j]){
dfs(j);
low[s]=min(low[s],low[j]);
}
else if(!scc[j]){
low[s]=min(low[s],stx[j]);
}
}
if(low[s]==stx[s]){
scccnt++;
while(){
int u=S.top();
S.pop();
scc[u]=scccnt;
if(s==u)break;
}
}
} void setscc(){
memset(stx,,sizeof(stx));
memset(scc,,sizeof(scc));
memset(id,,sizeof(id));
memset(od,,sizeof(od));
numi=numo=t=scccnt=;
for(int i=;i<=n;++i)if(!stx[i])dfs(i);
if(scccnt!=){
for(int i=;i<=n;++i){
for(int j=head[i];~j;j=nxt[j]){
int k=point[j];
if(scc[i]!=scc[k]){
id[scc[i]]++;
od[scc[k]]++;
if(id[scc[i]]==)numi++;
if(od[scc[k]]==)numo++;
}
}
}
numi=scccnt-numi;
numo=scccnt-numo;
}
} int main(){
int m;
while(scanf("%d%d",&n,&m)!=EOF){
init();
while(m--){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
setscc();
printf("%d\n",max(numi,numo));
}
return ;
}

UVALive4287 hdu2767 hdu3836 强连通的更多相关文章

  1. UVALive-4287 Proving Equivalences 有向图的强连通分量+缩点

    题意:有n个命题,已知其中的m个推导,要证明n个命题全部等价(等价具有传递性),最少还需要做出几次推导. 思路:由已知的推导可以建一张无向图,则问题变成了最少需要增加几条边能使图变成强连通图.找出所有 ...

  2. hdu2767 Proving Equivalences --- 强连通

    给一个图,问至少加入�多少条有向边能够使图变成强连通的. 原图是有环的,缩点建图,在该DAG图上我们能够发现,要使该图变成强连通图必须连成环 而加入�最少的边连成环,就是把图上入度为0和出度为0的点连 ...

  3. hdu2767强连通加缩点

    https://vjudge.net/contest/156688#problem/B 题目说了一大堆,前面的没有用,就是让你判断要加几条边才能强连通,用到缩点的知识 二重循环,判断邻接表下一个点是不 ...

  4. UVALive-4287 Proving Equivalences (有向图的强连通分量)

    题目大意:有n个命题,已知其中的m个推导,要证明n个命题全部等价(等价具有传递性),最少还需要做出几次推导. 题目分析:由已知的推导可以建一张无向图,则问题变成了最少需要增加几条边能使图变成强连通图. ...

  5. hdu2767(图的强连通)

    //题意:问需要添加几条边使得这张图成为每个点都等价(强连通图) 我们先把图中的强连通分量缩点 可能他本身就是满足条件,那么直接输出0 经过缩点后,就可以把强连通分量看成一个个独立的点,在这张图上搞一 ...

  6. 有向连通图增加多少边构成强联通(hdu3836,poj1236)

    hdu3836 求出强分量后缩点处理得到分支图,对分支图的每个强连通分量统计出度和入度.需要的边数就是:统计 入度=0 的顶点数 和 出度=0 的顶点数,选择两者中较大的一个,才能确保一个强连通图. ...

  7. LA 4287 等价性证明(强连通分量缩点)

    https://vjudge.net/problem/UVALive-4287 题意: 给出n个结点m条边的有向图,要求加尽量少的边,使得新图强连通. 思路:强连通分量缩点,然后统计缩点后的图的每个结 ...

  8. 【强连通分量】Proving Equivalences

    [题目链接]hdu-2767 [题目描述] Consider the following exercise, found in a generic linear algebra textbook. L ...

  9. HDU5934 强连通分量

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5934 根据距离关系建边 对于强连通分量来说,只需引爆话费最小的炸弹即可引爆整个强连通分量 将所有的强连通分 ...

随机推荐

  1. Android Studio 配置JPush

    1.在JPush官方下载 JPush SDK(jpush-android-arm-2.1.0.zip),我下载的是2.1.0: 2.解压下载好的压缩包(jpush-android-arm-2.1.0. ...

  2. C++指针详解(二)

    指针是C/C++编程中的重要概念之一,也是最容易产生困惑并导致程序出错的问题之一.利用指针编程可以表示各种数据结构,通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯:指针能 ...

  3. C++使用POST方法向网页提交数据-----C++发送HTTP数据获取Google天气预报

    例1:C++使用POST方法向网页提交数据    转自:http://www.it165.net/pro/html/201208/3534.html 在C++中可以使用POST方法向网页中提交数据,这 ...

  4. SQL server 与Oracle开发比较

    ●概念上区别 1.Oracle 是一种对象关系数据库管理系统(ORDBMS),而Sql server 只是关系型数据库管 理系统(RDBMS). 2.Oracle使用Internet文件系统,该系统基 ...

  5. Titanium vs PhoneGap

    http://mobile.51cto.com/Titanium-318049.htm http://www.ibm.com/developerworks/cn/opensource/os-titan ...

  6. HackRF实现无线门铃信号分析重放

    文章特点:数据解码方面实在是没什么信心,存在分析错乱的可能性,所幸发出来共同探讨,恳请鞭策. 0x01 概述 这是一款工作在315Mhz频段的无线遥控门铃,根据查阅官方手册以及芯片信息,确定其采用了e ...

  7. iOS 在UILabel显示不同的字体和颜色

    转自:http://my.oschina.net/CarlHuang/blog/138363 在项目开发中,我们经常会遇到在这样一种情形:在一个UILabel 使用不同的颜色或不同的字体来体现字符串, ...

  8. 解决Xcode7.1插件安装的办法

    现象一. 运行安装后,没有出现在菜单上. 1. 到githup上下载Alcatraz project https://github.com/supermarin/Alcatraz2. 打开终端 3. ...

  9. Logwatch的配置与使用

    Logwatch是使用 Perl 开发的一个日志分析工具 Logwatch能够对Linux 的日志文件进行分析,并自动发送mail给相关处理人员,可定制需求 Logwatch的mail功能是借助宿主系 ...

  10. Fix a corrupted user profile

    Fix a corrupted user profile Applies to Windows 7 Your user profile is a collection of settings that ...