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\n");
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\n",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\n",ans);
182         for(int i=1;i<=n;i++)
183         {
184             if(f[co[i]]==ans)
185             t[++tott]=i;
186         }
187         printf("%d\n",tott);
188         for(int i=1;i<=tott;i++)
189         {
190             printf("%d ",t[i]);
191         }
192         return 0;
193     }
194 }
View Code

 

posted @ 2019-03-18 17:42  snowy2002  阅读(218)  评论(0编辑  收藏  举报