poj 1236 Network of Schools(强连通、缩点、出入度)

题意:给出一个有向图。1:问至少选出多少个点,才能沿有向边遍历所有节点。2:问至少加多少条有向边,使原图强连通。

分析:第一个问题,缩点后找所有树根(入度为0)。第二个问题,分别找出入度为0和出度为0的所有点,去最大值即为答案。

  关于第二个问题,与这道题很相似。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<stack>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 const int MAXN=111;
  8 
  9 struct Edge{
 10     int v,next;
 11     Edge(){}
 12     Edge(int _v,int _next):v(_v),next(_next){}
 13 }edge[MAXN*MAXN];
 14 
 15 int pre[MAXN],low[MAXN],sccno[MAXN],dfs_clock,scc_cnt;
 16 int head[MAXN],tol;
 17 
 18 int outmark[MAXN],inmark[MAXN];
 19 
 20 stack<int>stk;
 21 
 22 void init()
 23 {
 24     tol=0;
 25     memset(head,-1,sizeof(head));
 26 }
 27 
 28 void add(int u,int v)
 29 {
 30     edge[tol]=Edge(v,head[u]);
 31     head[u]=tol++;
 32 }
 33 
 34 void dfs(int u)
 35 {
 36     int v;
 37     pre[u]=low[u]=++dfs_clock;
 38     stk.push(u);
 39     for(int i=head[u];i!=-1;i=edge[i].next)
 40     {
 41         v=edge[i].v;
 42 
 43         if(!pre[v]){
 44             dfs(v);
 45             low[u]=min(low[u],low[v]);
 46         }else if(!sccno[v])
 47             low[u]=min(low[u],pre[v]);
 48     }
 49     if(pre[u]==low[u]){
 50         scc_cnt++;
 51         do{
 52             v=stk.top();
 53             stk.pop();
 54             sccno[v]=scc_cnt;
 55         }while(u!=v);
 56     }
 57 }
 58 
 59 void find_scc(int n)
 60 {
 61     dfs_clock=scc_cnt=0;
 62     memset(pre,0,sizeof(pre));
 63     memset(low,0,sizeof(low));
 64     memset(sccno,0,sizeof(sccno));
 65 
 66     for(int i=1;i<=n;i++)
 67         if(!pre[i])
 68             dfs(i);
 69 }
 70 
 71 int main()
 72 {
 73     int n;
 74     scanf("%d",&n);
 75     init();
 76     for(int u=1;u<=n;u++)
 77     {
 78         while(1)
 79         {
 80             int v;
 81             scanf("%d",&v);
 82             if(!v)
 83                 break;
 84             add(u,v);
 85         }
 86     }
 87 
 88     find_scc(n);
 89 
 90     memset(inmark,0,sizeof(inmark));
 91     memset(outmark,0,sizeof(outmark));
 92     for(int i=1;i<=n;i++)
 93     {
 94         for(int j=head[i];j!=-1;j=edge[j].next)
 95             if(sccno[i]!=sccno[edge[j].v]){
 96                 inmark[sccno[edge[j].v]]++;
 97                 outmark[sccno[i]]++;
 98             }
 99     }
100     int inans=0,outans=0;
101     for(int i=1;i<=scc_cnt;i++)
102     {
103         if(!inmark[i])
104             inans++;
105         if(!outmark[i])
106             outans++;
107     }
108     printf("%d\n",inans);
109     if(scc_cnt==1)
110         printf("0\n");
111     else
112         printf("%d\n",max(inans,outans));
113     return 0;
114 }
View Code

 

posted @ 2013-10-02 16:17  Thousand Sunny  阅读(228)  评论(0编辑  收藏  举报