好吧~图论的学习该告一段落了。这个题很有意思:
说有几个学校,相互传递盗版软件,为单向传递关系。问给最少几个学校盗版软件,可以使得全部的学校都有盗版软件。2问最少添加几个传递关系,使得不论城管消灭其中的一条传递线路,还是能够让所有的学校都通过一张盗版光盘传递完。
思路呢.... 很简单,对图中的强连通分量进行缩点,形成图G‘,这样去找入度为0的连通分量数即可。因为没有盗版软件必须要有源头,而如度为0的强连通分量没有源头,故发软件。
2.出度为零的连通分量和入度为零的强连通分量中值最大的即为答案。因为要连成环就不怕城管了,所以入度和出度为零的连边就好了~
求解强连通分量比较熟悉了~ 很快的写代码1Y
#include<iostream>
#include<stack>
#define MAXN 105
using namespace std;struct Node
{int v;Node *next;
}Edge[MAXN*MAXN],*ptr[MAXN];Node Edge2[MAXN];
Node *ptr2[MAXN];int DFN[MAXN],LOW[MAXN];
int DEP,SCCNum;
int N,Point[MAXN];
bool inS[MAXN];
int min( int a,int b ){ return a<b?a:b; }void addEdge( int u,int v )
{Node *p=&Edge[++DEP];p->v=v;p->next=ptr[u];ptr[u]=p;
}
void addEdge2( int u,int v )
{Node *p=&Edge2[++DEP];p->v=v;p->next=ptr2[u];ptr2[u]=p;
}stack<int>myStack;
void Tarjan( int u )
{myStack.push(u);inS[u]=true;DFN[u]=LOW[u]=++DEP;Node *p=ptr[u];while( p ){if( DFN[p->v]==0 ){Tarjan( p->v );LOW[u]=min( LOW[u],LOW[p->v]);}else if( inS[p->v] )LOW[u]=min(LOW[u],DFN[p->v] );p=p->next;}if( DFN[u]==LOW[u] ){int v;++SCCNum;do{v=myStack.top();myStack.pop();inS[v]=0;Point[v]=SCCNum;}while( u!=v );}
}int main()
{while( scanf( "%d",&N )!=EOF ){memset( DFN,0,sizeof(DFN) );memset( LOW,0,sizeof(LOW) );memset( inS,0,sizeof(inS) );memset( Point,0,sizeof(Point) );SCCNum=0;int i,j;for( i=0;i<=N;i++ )ptr[i]=ptr2[i]=NULL;DEP=0;for( i=1;i<=N;i++ ){while( true ){scanf( "%d",&j );if( j==0 )break;addEdge( i,j );}}DEP=0;for( i=1;i<=N;i++ )if( DFN[i]==0 )Tarjan( i );DEP=0;for( i=1;i<=N;i++ ){Node *p=ptr[i];while( p ){if( Point[i]!=Point[p->v] )addEdge2( Point[i],Point[p->v] );p=p->next;}}int inD[MAXN],outD[MAXN];memset( inD,0,sizeof(inD) );memset( outD,0,sizeof(outD) );for( i=1;i<=SCCNum;i++ ){Node *p=ptr2[i];while( p ){outD[i]++;inD[p->v]++;p=p->next;}}int cntI,cntO;cntI=cntO=0;//printf( "%d\n",SCCNum );for( i=1;i<=SCCNum;i++ ){if( inD[i]==0 )cntI++;if( outD[i]==0 )cntO++;}printf( "%d\n",cntI );if( SCCNum==1 )printf( "0\n" );elseprintf( "%d\n",cntI>cntO?cntI:cntO );}return 0;
}