hdu 1827 有向图缩点看度数

题意:给一个有向图,选最少的点(同时最小价值),从这些点出发可以遍历所有。
思路:先有向图缩点,成有向树,找入度为0的点即可。
下面给出有向图缩点方法:

用一个数组SCC记录即可,重新编号,1....num,具体方法如下代码详见。


#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
using namespace std;
int n,m;
vector<vector<int> >v(10010);
int vis[10010];int dfn[10010];int low[10010];int times=0;
int num=0;
int instack[10010];stack<int>s;   //有向图的连通性,用栈。
int scc[1010]; int w[1010]; int neww[1010];
int ind[1010];
void tarjarn(int u)
{
   dfn[u]=low[u]=++times;
   instack[u]=1;
   s.push(u);
   for(int i=0;i<v[u].size();i++)
   {
       int vv=v[u][i];
       if(!vis[vv])
       {
           vis[vv]=1;
           tarjarn(vv);
           if(low[vv]<low[u])low[u]=low[vv];  //孩子可以到达,我必然也可以到达。
       }
       else if(instack[vv])      //注意,更新时要有在栈中条件,代表该孩子(其实是祖先)我能到达,而且是属于当前SCC。
       {
           if(dfn[vv]<low[u])low[u]=dfn[vv]; //能到达的祖先,所以更新。
       }
   }
   if(dfn[u]==low[u])    
   {
       num++;int cur;
       int min=w[u];   //找这个SCC权最小的权。
       do
       {
           cur=s.top();
           if(w[cur]<min)min=w[cur];
           s.pop();
           instack[cur]=0;
           scc[cur]=num;
       }while(cur!=u);
       neww[num]=min;
   }
}
int main()
{
    while(~scanf("%d %d",&n,&m))
    {
        int ta,tb;
        for(int i=0;i<=n;i++)
          {
              v[i].clear();
              neww[i]=ind[i]=w[i]=instack[i]=dfn[i]=low[i]=vis[i]=0;
          }
          times=0;
       for(int i=1;i<=n;i++)
       {
          scanf("%d",&w[i]);
       }
        for(int i=0;i<m;i++)
        {
            scanf("%d %d",&ta,&tb);
            v[ta].push_back(tb);
        }
        num=0;
        for(int i=1;i<=n;i++)
         {
               if(!vis[i])
                   {   vis[i]=1;
                       tarjarn(i);
                   }
         }
         int sum=0;int count=0; 
        for(int i=1;i<=n;i++)           //遍历边。
        {
            for(int j=0;j<v[i].size();j++)
             {
                 if(scc[i]!=scc[v[i][j]])
                   {
                     ind[scc[v[i][j]]]++;
                   }
             }
        }
         for(int i=1;i<=num;i++)
        {
            if(ind[i]==0)
            {
                sum+=neww[i];
                count++;
            }
        }
        printf("%d %d\n",count, sum);
    }
    return 0;
}



posted @ 2014-04-20 17:06  天羽屠龙舞  阅读(152)  评论(0编辑  收藏  举报