您的位置:首页 > 产品设计 > UI/UE

【 UVALive - 4287】Proving Equivalences (SCC缩点)

2016-03-17 16:45 471 查看
题意:

  给出N个命题,要求你证明这N个命题的等价性

  比如有4个命题a,b,c,d,我们证明a<->b, b<->c,c<->d,每次证明都是双向的,因此一共用了6次推导
如果换成证明a->b,b->c,c->d,d->a,每次证明都是单向的,而只需4次就可以证明所有命题的等价性
现在给出M个命题证明,问还需要证明几个,才可以保证N个命题等价。

分析:

  缩点后求DAG中入度为0和出度为0的联通块的较大值。

代码如下:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#define Maxn 20010
#define Maxm 50010

int first[Maxn],dfn[Maxn],low[Maxn],sta[Maxn],scc[Maxn];
bool ru[Maxn],chu[Maxn];
int cnt,sl,cl;

struct node
{
int x,y,next;
}t[Maxm];

int mymin(int x,int y) {return x<y?x:y;}
int mymax(int x,int y) {return x>y?x:y;}

void ffind(int x)
{
dfn[x]=low[x]=++cnt;
sta[++sl]=x;
for(int i=first[x];i;i=t[i].next)
{
int y=t[i].y;
if(dfn[y]==0)
{
ffind(y);
low[x]=mymin(low[x],low[y]);
}
else if(scc[y]==0) low[x]=mymin(low[x],dfn[y]);
}
if(low[x]==dfn[x])
{
cl++;
while(1)
{
int z=sta[sl--];
scc[z]=cl;
if(z==x) break;
}
}
}

int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int i,n,m,r=0,c=0;
scanf("%d%d",&n,&m);
memset(first,0,sizeof(first));
memset(dfn,0,sizeof(dfn));
memset(scc,0,sizeof(scc));
cnt=0;sl=0;cl=0;
for(i=1;i<=m;i++)
{
scanf("%d%d",&t[i].x,&t[i].y);
t[i].next=first[t[i].x];first[t[i].x]=i;
}
for(i=1;i<=n;i++) if(dfn[i]==0) ffind(i);
memset(ru,1,sizeof(ru));
memset(chu,1,sizeof(chu));
for(i=1;i<=m;i++) if(scc[t[i].x]!=scc[t[i].y])
chu[scc[t[i].x]]=0,ru[scc[t[i].y]]=0;
for(i=1;i<=cl;i++) r+=ru[i],c+=chu[i];
if(cl==1) printf("0\n");
else printf("%d\n",mymax(r,c));
}
return 0;
}


[LA4287]

2016-03-17 16:46:42
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: