zoukankan      html  css  js  c++  java
  • 【tarjan+缩点】POJ1236[IOI1996]-Network of Schools

    【题意】

    见:http://blog.csdn.net/ascii991/article/details/7466278

    【思路】

    缩点+tarjan,思路也可以到上面的博客去看。(吐槽:这道题其实我没有AC。我过了当年IOI的数据,而把别人AC掉的程序带进去,明显过不了IOI的数据!求POJ修正一下!)我在这里引用一下:

    找强连通分量,缩点。记f[i]为缩完点后的新图中各点入度,g[i]为出度,ans1为f[i]==0的点的数目,ans2为g[i]==0的点的数目则第一问为ans1,第二问则为max{ans1,ans2}。

    至于第二问的解释,我的想法是对于得到的DAG图,考虑其中的出度为0的点和入度为0的点组成的点集V,将这些点相连,最多这需要max{ans1,ans2}条边,就能使整个图成为强连通分量。

    但是请注意,大家可能都没发现,这个结论的前提是DAG图是连通的情况下才成立。如果DAG图有多个连通分量,则还要考虑将多个连通分量合并的所需代价。幸运的是,这道题保证了只有一个连通分量。(题目第一句话所说)

    【错误点】

    1.tarjan要进行多次,详见程序注释

    2.循环从0开始还是从1开始要看清楚!

    3.但只有一个连通分量的时候,不需要再增加边!

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<vector>
      6 #include<stack>
      7 using namespace std;
      8 const int MAXN=100+5;
      9 int n;//学校的总数 
     10 int u[MAXN],v[MAXN];//记录每一条边的起始点和终点
     11 int sp[MAXN];//记录缩点之后每个点对应的编号
     12 int tot=0;//有向图中边的总数 
     13 int vis[MAXN]; 
     14 int instack[MAXN];
     15 int dfn[MAXN],low[MAXN];
     16 int indegree[MAXN],outdegree[MAXN];//记录缩点后的每一个点的入度与出度 
     17 vector<int> E[MAXN]; 
     18 stack<int> S;
     19 int T=0;
     20 int cnt=0;//为缩点后的每一个点编号 
     21 
     22 void tarjan(int u)
     23 {
     24     dfn[u]=low[u]=++T;
     25     vis[u]=1;
     26     S.push(u);
     27     instack[u]=1;
     28     
     29     for (int i=0;i<E[u].size();i++)
     30     {
     31         int son=E[u][i];
     32         if (!vis[son])
     33         {
     34             tarjan(son);
     35             low[u]=min(low[son],low[u]);
     36         }
     37         else
     38         if (vis[son] && instack[son])
     39             low[u]=min(dfn[son],low[u]);
     40     }
     41     
     42     if (dfn[u]==low[u])
     43     {
     44         cnt++;
     45         int x;
     46         do
     47         {
     48              x=S.top();
     49              S.pop();
     50              sp[x]=cnt;
     51              instack[x]=0;
     52         }while (x!=u);
     53     }
     54 } 
     55 
     56 void init()
     57 {
     58     memset(vis,0,sizeof(vis));
     59     memset(instack,0,sizeof(instack));
     60     scanf("%d",&n);
     61     for (int i=1;i<=n;i++)
     62     {
     63         int to;
     64         while (scanf("%d",&to) && to)
     65         {
     66             tot++;
     67             u[tot]=i;v[tot]=to;
     68             E[i].push_back(to);
     69         }
     70     }
     71 }
     72 
     73 void find()
     74 {
     75     memset(indegree,0,sizeof(indegree));
     76     memset(outdegree,0,sizeof(outdegree));
     77     if (cnt>1)
     78     {
     79         for (int i=1;i<=tot;i++)
     80         /*错误点:写成了i=0;i<tot,导致有时候没有进入循环!*/
     81         {
     82             if (sp[u[i]]!=sp[v[i]])
     83             {
     84                 outdegree[sp[u[i]]]++;
     85                 indegree[sp[v[i]]]++;
     86             }//找出缩点后各点的出度和入度 
     87         }
     88         
     89         int noin=0,noout=0;
     90         for (int i=1;i<=cnt;i++)
     91         {
     92             if (indegree[i]==0) noin++;
     93             if (outdegree[i]==0) noout++;
     94         }
     95         cout<<noin<<endl;
     96         cout<<max(noin,noout)<<endl;
     97     }
     98     else if (cnt==1) printf("1
    
    ");
     99 }
    100 
    101 int main()
    102 {
    103     init();
    104     for (int i=1;i<=n;i++) if (vis[i]==0) tarjan(i);
    105     /*错误点:一开始直接tarjan(1)了,导致有一些学校没有被访问到!每次随机从没有访问的某个结点开始!*/ 
    106     find();
    107     return 0;
    108 }
  • 相关阅读:
    常用正则表达式
    python 正则表达式 匹配指定字符遇到问题记录
    python 正则表达式 匹配指定字符
    python 正则表达式
    vim多窗口, 常用命令集
    linux寻找文件
    配置VIM环境
    本地计算机上的XXX服务启动后停止,某些服务在未由其它服务或程序使用时将自动停止
    Centos7安装python3、numpy、scipy、matplotlib、pandas等
    vmware虚拟机安装CentOS7无法上网以及键盘无法输入情况解决
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5202432.html
Copyright © 2011-2022 走看看