POJ 1236(tarjan 强连通分量 缩点)

来源:互联网 发布:怎么看淘宝商品编号 编辑:程序博客网 时间:2024/06/01 22:48

POJ1236

题目大意

问,对于一个DAG(又向无环图):
1.至少要选几个点,才能从这些点出发到达所有点
2.至少加入几条边,就能从图中任何一个点出发到达所有点

分析

先求DAG的强连通分量数,再缩点,可以用tarjan算法来做。
第一个问题:不难想到答案就是缩点之后入度为0的点的个数
第二个问题:设缩点后入度为0的个数是n,出度为0的个数是m,至少添加边的条数就是max(n,m)

代码

#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<cstdlib>#include<queue>#include<map>#include<algorithm>#include<set>#include<stack>using namespace std;const int MAXN=105;int n;int DFN[MAXN];int LOW[MAXN];int vis[MAXN];int belong[MAXN];//belong[i]表示i属于缩点后的哪个节点int cnt;int out[MAXN];int in[MAXN];int tot;struct Edge{      int v;      int next;}edge[MAXN*MAXN];int edgecount;int head[MAXN];void Init(){      edgecount=0;      memset(head,-1,sizeof(head));}void Add_edge(int u,int v){      edge[++edgecount].v=v;      edge[edgecount].next=head[u];      head[u]=edgecount;}stack<int > St;void Tarjan(int u)//从节点x开始搜索{     DFN[u]=LOW[u]=++tot;     vis[u]=1;//为1表示在队列里面     St.push(u);     for(int k=head[u];k!=-1;k=edge[k].next)     {           int v=edge[k].v;           if(!DFN[v])//还未访问过           {                 Tarjan(v);                 LOW[u]=min(LOW[u],LOW[v]);           }           else if(vis[v])//被访问过,还在队列里           {                 LOW[u]=min(LOW[u],DFN[v]);           }     }     if(LOW[u]==DFN[u])     {           int x;           ++cnt;           while(1)           {                 x=St.top();                 St.pop();                 vis[x]=0;                 belong[x]=cnt;                 if(x==u)break;           }     }}void Solve(){    tot=0;    cnt=0;//缩点后的点数    memset(DFN,0,sizeof(DFN));    memset(LOW,0,sizeof(LOW));    memset(vis,0,sizeof(vis));    memset(in,0,sizeof(in));    memset(out,0,sizeof(out));    while(!St.empty()) St.pop();    for(int i=1;i<=n;i++)    {          if(DFN[i]==0)Tarjan(i);    }    for(int u=1;u<=n;u++)    {          for(int k=head[u];k!=-1;k=edge[k].next)          {                int v=edge[k].v;                if(belong[u]!=belong[v])                {                      out[belong[u]]++;                      in[belong[v]]++;                }          }    }    int ans1=0;    int ans2=0;    for(int i=1;i<=cnt;i++)    {          if(in[i]==0)ans1++;          if(out[i]==0)ans2++;    }    ans2=max(ans1,ans2);    if(cnt==1)printf("1\n0\n");    else printf("%d\n%d\n",ans1,ans2);}int main(){    int v;    while(scanf("%d",&n)!=EOF)    {          Init();          for(int u=1;u<=n;u++)          {               while(scanf("%d",&v) && v!=0)Add_edge(u,v);          }          Solve();    }    return 0;}
0 0