这题好久前就做过了...结果过了几个月还是不会...题解也看不懂...不过参考题解的一部分倒是懂了。
首先把每个人当做一个节点,从每个人向他要告诉的那个人连边,产生一张有向图。显然,一个人如果不在环上,那么就永远不可能听到自己的信息;一个人如果在环上,那么就会在进行“包含这个点的长度最小的环的长度"轮之后听到自己的信息。现在要求所有人听到自己信息的轮数的最小值,也就是要求图的最小环。
裸的最小环应该是floyed,$O(n^3)$。显然是不行的。可以注意到一点,就是这题的图中每个点最多只有一条出边。那么,一个点显然不可能出现在多个环里面。也就是说,一个点要么不在环中,要么只在一个单独的环中。因此,可以先把不在环上的点去掉;对于每个环,只需要从环上任意一点出发dfs一遍求出回到自身路径长度就行。
如何把不在环上的点去掉?可以用拓扑排序。拓扑排序做一遍只会留下环上点。
错误记录:
1.deque不会用,47行写成pop_back()
2.写题过程中记错题意,58行写成max
1 //#pragma comment(linker, "/STACK:10240000,10240000") 2 #include<cstdio> 3 //#pragma GCC optimize (2) 4 #include<deque> 5 #include<malloc.h> 6 using namespace std; 7 struct E 8 { 9 int to,nxt; 10 }e[400100]; 11 int f1[200100],ne,in[200100]; 12 deque<int> q; 13 bool boo[200100]; 14 int n,ans=0x3f3f3f3f; 15 int dfs(int x) 16 { 17 boo[x]=1; 18 // if(dep==43429) 19 // { 20 // printf("1"); 21 // } 22 for(int k=f1[x];k!=0;k=e[k].nxt) 23 if(!boo[e[k].to]) 24 return dfs(e[k].to)+1; 25 } 26 int main() 27 { 28 //int size = 256 << 20; // 256MB //windows上可能需要手动扩栈,不然会爆栈 29 //char *p = (char*)malloc(size) + size; 30 //__asm__("movl %0, %%esp\n" :: "r"(p)); 31 //freopen("testdata.in","r",stdin); 32 int i,a,t,k; 33 scanf("%d",&n); 34 for(i=1;i<=n;i++) 35 { 36 scanf("%d",&a); 37 e[++ne].to=a; 38 e[ne].nxt=f1[i]; 39 f1[i]=ne; 40 in[a]++; 41 } 42 for(i=1;i<=n;i++) 43 if(in[i]==0) 44 q.push_back(i); 45 while(!q.empty()) 46 { 47 t=q.front();q.pop_front(); 48 boo[t]=1; 49 for(k=f1[t];k!=0;k=e[k].nxt) 50 { 51 in[e[k].to]--; 52 if(in[e[k].to]==0) 53 q.push_back(e[k].to); 54 } 55 } 56 for(i=1;i<=n;i++) 57 if(!boo[i]) 58 ans=min(ans,dfs(i)+1); 59 printf("%d",ans); 60 return 0; 61 }
时间: 2024-12-13 23:34:56