• P3436 [POI2006]PRO-Professor Szu


    P3436 [POI2006]PRO-Professor Szu

    题目描述

    n个别墅以及一个主建筑楼,从每个别墅都有很多种不同方式走到主建筑楼,其中不同的定义是(每条边可以走多次,如果走边的顺序有一条不同即称两方式不同)。

    询问最多的不同方式是多少,以及有多少个别墅有这么多方式,按照顺序输出别墅编号。

    如果最多不同方式超过了36500那么都视作zawsze

    输入输出样例

    输入样例#1: 
    3 5
    1 2
    1 3
    2 3
    3 4
    3 4
    输出样例#1: 
    4
    1
    1

    这题反向建个图,缩个点,跑个topo就没了?显然没有这么容易,这里说一下题目的坑点。首先这个题目是要求从n+1号结点出发,那么如果n+1号点不能到达所有的结点会怎么样呢?

    看上面这张图,假设这是我们的反向图,按理说我们应该从6号点开始topo,但是5号点自始至终都不会入队,所以说4号点的入度就不可能减到0,这样的话4号点就无法进行topo,那么这样的答案也肯定是错的。要解决这个问题也很简单,就是在缩点时只缩从n+1号点能到达的结点,然后再建新图,而且建的新图中不能含有从n+1号点不能到达的结点。

     1 tarjan(n+1);//这里只从n+1号点开始缩点 
     2 for(int i=1;i<=n+1;i++)
     3 {
     4     if(!dfn[i]) continue;//如果某一个点是n+1号点无法到达的,那么就不能把这个点加到图中 
     5     for(int j=last[i];j;j=g[j].next)
     6     {
     7         int v=g[j].to;
     8         if(co[i]!=co[v])
     9         {
    10             add1(co[i],co[v]);
    11             de[co[v]]++;
    12         }
    13     }
    14 }
    建图

    但是这样还是A不了,这又是为啥呢?原来是自环惹的祸。

    看上边的图,我们已经解决了五号点这个从起点无法到达的点的问题了,但是如果四号点给你来一个自环,那不好意思,你又挂了,要是按正常的缩点的话,四号点应该自己单独成为一个强联通分量,按理应该不需要管他,直接dp就好了,但是如果有自环,那么只要经过4号点,方案数就一定会变为正无穷,所以说,自环也是一定要考虑在内的,但是该怎么做呢,这个就更简单了,只需在读入的时候加个特判就好了,最后统计是把自环也当成环处理即可。

    1 for(int i=1;i<=m;i++)
    2 {
    3     aa=read();bb=read();
    4     if(aa==bb)
    5     b[aa]=1;//如果有自环,就标记一下; 
    6     add(bb,aa);
    7 }
    判断自环

    然而这样还是A不了,这究竟是为什么呢?后来经我计算发现36500*1000000=36500000000

    然后就GG了,果断#define int long long,然后就A了……

    真的是巨坑无比的一道题目。

      1 #include<iostream>
      2 #include<string>
      3 #include<cmath>
      4 #include<cstring>
      5 #include<cstdio>
      6 #include<stack>
      7 #include<queue>
      8 #define int long long 
      9 #define maxn 2000005
     10 using namespace std;
     11 
     12 struct edge
     13 {
     14     int next,to;
     15 }g[maxn<<1],g1[maxn<<1];
     16 int n,m,num,tot,col,num1,aa,bb,cnt,tott,pd,de[maxn],t[maxn];
     17 long long ans;
     18 long long f[maxn];
     19 int last[maxn],dfn[maxn],low[maxn],co[maxn],last1[maxn],a[maxn],b[maxn],c[maxn];
     20 stack<int>s;
     21 stack<int>ss;
     22 
     23 inline int read()
     24 {
     25     char c=getchar();
     26     int x=1,res=0;
     27     while(c<'0'||c>'9')
     28     {
     29         if(c=='-')
     30         x=-1;
     31         c=getchar();
     32     }
     33     while(c>='0'&&c<='9')
     34     {
     35         res=res*10+(c-'0');
     36         c=getchar();
     37     }
     38     return x*res;
     39 }
     40 
     41 void add(int from,int to)
     42 {
     43     g[++num].next=last[from];
     44     g[num].to=to;
     45     last[from]=num;
     46 }
     47 
     48 void add1(int from,int to)
     49 {
     50     g1[++num1].next=last1[from];
     51     g1[num1].to=to;
     52     last1[from]=num1;
     53 }
     54 
     55 void tarjan(int u)
     56 {
     57     dfn[u]=low[u]=++tot;
     58     s.push(u);
     59     for(int i=last[u];i;i=g[i].next)
     60     {
     61         int v=g[i].to;
     62         if(!dfn[v])
     63         {
     64             tarjan(v);
     65             low[u]=min(low[u],low[v]);
     66         }
     67         else if(!co[v])
     68         {
     69             low[u]=min(low[u],dfn[v]);
     70         }
     71     }
     72     if(low[u]==dfn[u])
     73     {
     74         col++;cnt=0;
     75         for(;;)
     76         {
     77             int x=s.top();s.pop();
     78             co[x]=col;
     79             cnt++;
     80             if(x==u) break;
     81         }
     82         a[col]=cnt;
     83     }
     84 }
     85 
     86 void topo()
     87 {
     88     ss.push(co[n+1]);
     89     if(c[co[n+1]]==1)
     90     {
     91         f[co[n+1]]=36501;
     92     }
     93     else
     94     {
     95         f[co[n+1]]=1;
     96     }
     97     while(ss.size())
     98     {
     99         int u=ss.top();ss.pop();
    100         for(int i=last1[u];i;i=g1[i].next)
    101         {
    102             int v=g1[i].to;
    103             if(c[v]==1)
    104             {
    105                 f[v]=36501;
    106             }
    107             else
    108             {
    109                 f[v]+=f[u];
    110             }
    111             de[v]--;
    112             if(de[v]==0)
    113             ss.push(v);
    114         }
    115     }
    116 }
    117 
    118 signed main()
    119 {
    120     n=read();m=read();
    121     for(int i=1;i<=m;i++)
    122     {
    123         aa=read();bb=read();
    124         if(aa==bb)
    125         b[aa]=1;//如果有自环,就标记一下; 
    126         add(bb,aa);
    127     }
    128     tarjan(n+1);//这里只从n+1号点开始缩点 
    129     for(int i=1;i<=n+1;i++)
    130     {
    131         if(!dfn[i]) continue;//如果某一个点是n+1号点无法到达的,那么就不能把这个点加到图中 
    132         for(int j=last[i];j;j=g[j].next)
    133         {
    134             int v=g[j].to;
    135             if(co[i]!=co[v])
    136             {
    137                 add1(co[i],co[v]);
    138                 de[co[v]]++;
    139             }
    140         }
    141     }
    142     for(int i=1;i<=n+1;i++)
    143     {
    144         if(b[i]==1)
    145         {
    146             c[co[i]]=1;
    147         }
    148         if(a[co[i]]>1)
    149         {
    150             c[co[i]]=1;
    151         }
    152     }
    153     topo();
    154     for(int i=1;i<=n;i++)
    155     {
    156         if(f[co[i]]>36500)
    157         {
    158             pd=1;
    159         }
    160         ans=max(ans,f[co[i]]);
    161     }
    162     if(pd==1)
    163     {
    164         printf("zawsze
    ");
    165         for(int i=1;i<=n;i++)
    166         {
    167             if(f[co[i]]>36500)
    168             {
    169                 t[++tott]=i;
    170             }
    171         }
    172         printf("%d
    ",tott);
    173         for(int i=1;i<=tott;i++)
    174         {
    175             printf("%d ",t[i]);
    176         }
    177         return 0;
    178     }
    179     else 
    180     {
    181         printf("%lld
    ",ans);
    182         for(int i=1;i<=n;i++)
    183         {
    184             if(f[co[i]]==ans)
    185             t[++tott]=i;
    186         }
    187         printf("%d
    ",tott);
    188         for(int i=1;i<=tott;i++)
    189         {
    190             printf("%d ",t[i]);
    191         }
    192         return 0;
    193     }
    194 }
    View Code
  • 相关阅读:
    [多线程]使用信号量进行同步
    [多线程]互斥锁与信号量的区别
    [多线程]环形缓冲区以及多线程条件同步
    [多线程]LINUX c多线程编程-线程初始化与建立
    [STL]bitset使用
    [算法]败者树
    【Rollo的Python之路】Python:字符串内置函数
    【Rollo的Python之路】Python:字典的学习笔记
    【Rollo的Python之路】 购物车程序练习
    【Rollo的Python之路】Python 元组的学习
  • 原文地址:https://www.cnblogs.com/snowy2002/p/10553654.html
Copyright © 2020-2023  润新知