poj 1236+hdu2767 有向图 缩点+看度数(tarjan)

1236题意:一个有向图,1,求至少从几个点出发可以遍历该图,2:,求至少添加多少边,使强连通。而,HDU的只有后面一问。

解;先缩点,第一问只需找所有入度为0的点即可。,第2问,max(入度为0的点,出度为0点)。也写了2个小时。。虽然1A,但是因为细节卡了,不应该。


代码详细说:

#include<iostream>   //0ms 1A poj1236
#include<vector>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
int n;
vector<vector<int> >edges(101);
int visited[101];
int low[101];
int dfn[101];
int ind[101];int outd[101];          //统计出入度
int Strongly_connected_branch[101];  //并为一个强连通,标记为1.2.3...
int num;int times;
stack<int>s;
bool instack[101];
void tarjan(int u)               //dfs
{ 
    low[u]=dfn[u]=times++;
    instack[u]=1;
    s.push(u);
    int len=edges[u].size();
    for(int i=0;i<len;i++)
    {
        int v=edges[u][i];
        if(visited[v]==0)          //小心细节!
        {
             visited[v]=1;
               tarjan(v);
            if(low[u]>low[v])low[u]=low[v];
        }
        else if(instack[v]&&low[u]>dfn[v])     //有向图,要问是否在栈中,后向边,V为U某个祖先
        {
            low[u]=dfn[v];
        }
    }
    if(dfn[u]==low[u])         //在一个SCC
    {
        num++;int temp;
         do
        {
             temp=s.top();
             instack[temp]=0;
            s.pop();
            Strongly_connected_branch[temp]=num;
        } while(temp!=u);
    }
}
void readin()            //读入数据
{
    scanf("%d",&n);
    int to;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&to);
        while(to!=0)
       {
           edges[i].push_back(to);
           scanf("%d",&to);
       }
    }
}
int ind0,outd0;
void initialize()             //初始化
{
    ind0=outd0=num=times=0;
}
void solve()             
{
    for(int i=1;i<=n;i++)        //原图未必连通
       if(visited[i]==0)
        {
            visited[i]=1;
            tarjan(i);
        }
     for(int i=1;i<=n;i++)     //自己思得:枚举所有边,在不同scc中的,这样统计其出入度,缩点只是把所有SCC分开
   {                           //这样统计,出入度为0的肯定没问题,但是是收缩后的图(原图中有几条边SCC间连任连几条)的出入度,
      int len=edges[i].size();
       for(int j=0;j<len;j++)     
       {
          int v=edges[i][j];
          if(Strongly_connected_branch[v]!=Strongly_connected_branch[i])
          {
            outd[Strongly_connected_branch[i]]++;
            ind[Strongly_connected_branch[v]]++;
          }
       }
    }
    for(int i=1;i<=num;i++)  
    {
        //cout<<"out:"<<outd[i]<<"in:"<<ind[i]<<endl;
       if(outd[i]==0)outd0++;
       if(ind[i]==0)ind0++;
    }
}
int main()
{
   readin();
   initialize();
   solve();
   int max0=outd0;
   if(num==1){printf("1
0
");return 0 ;}        //如果原来就强连通,特判
   if(ind0>max0)max0=ind0;
   printf("%d
%d
",ind0,max0);
   return 0;
}


#include<iostream>   //hdu 260ms
#include<vector>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
int n;int m;
vector<vector<int> >edges(20001);
int visited[20001];
int low[20001];
int dfn[20001];
int ind[20001];int outd[20001];          //统计出入度
int Strongly_connected_branch[20001];  //并为一个强连通,标记为1.2.3...
int num;int times;
stack<int>s;
bool instack[20001];
void tarjan(int u)
{
    low[u]=dfn[u]=times++;
    instack[u]=1;
    s.push(u);
    int len=edges[u].size();
    for(int i=0;i<len;i++)
    {
        int v=edges[u][i];
        if(visited[v]==0)          
        {
             visited[v]=1;
               tarjan(v);
            if(low[u]>low[v])low[u]=low[v];
        }
        else if(instack[v]&&low[u]>dfn[v])     //有向图,要问是否在栈中,后向边,V为U某个祖先
        {
            low[u]=dfn[v];
        }
    }
    if(dfn[u]==low[u])         //在一个SCC
    {
        num++;int temp;
         do
        {
             temp=s.top();
             instack[temp]=0;
            s.pop();
            Strongly_connected_branch[temp]=num;
        } while(temp!=u);
    }
}
void readin()
{
    scanf("%d%d",&n,&m);
    int from,to;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&from,&to);
        edges[from].push_back(to);
    }
}
int ind0,outd0;
void initialize()              //多组数据,必需初始化
{
    ind0=outd0=num=times=0;
    for(int i=0;i<=n;i++)
    {
        instack[i]=low[i]=dfn[i]=visited[i]=ind[i]=outd[i]=0;
        edges[i].clear();
        Strongly_connected_branch[i]=-1;
    }
}
void solve()
{
    for(int i=1;i<=n;i++)
       if(visited[i]==0)
        {
            visited[i]=1;
            tarjan(i);
        }
     for(int i=1;i<=n;i++)     //自己思得:枚举所有边,在不同scc中的,这样统计其出入度,缩点只是把所有SCC分开
   {                           //这样统计,出入度为0的肯定没问题,但是是收缩后的图(原图中有几条边SCC间连任连几条)的出入度,
      int len=edges[i].size();
       for(int j=0;j<len;j++)
       {
          int v=edges[i][j];
          if(Strongly_connected_branch[v]!=Strongly_connected_branch[i])
          {
            outd[Strongly_connected_branch[i]]++;
            ind[Strongly_connected_branch[v]]++;
          }
       }
    }
    for(int i=1;i<=num;i++)
    {
       if(outd[i]==0)outd0++;
       if(ind[i]==0)ind0++;
    }
}
int main()
{
    int tcase;
    scanf("%d",&tcase);
   while(tcase--)
   {
       initialize();
       readin();
       solve();
     int max0=outd0;
   if(num==1){printf("0
");continue;}
   if(ind0>max0)max0=ind0;
   printf("%d
",max0);
   }
   return 0;
}


原文地址:https://www.cnblogs.com/yezekun/p/3925816.html