1. 程式人生 > >CF 949C Data Center Maintenance——思路+SCC

CF 949C Data Center Maintenance——思路+SCC

stack turn pac truct urn oid clu cte add

題目:http://codeforces.com/contest/949/problem/C

可以想到可能是每組c有連邊的可能。

但別直接給c1、c2連邊,那樣之後會變得很不好做。

可以把一些限制放在連邊這個環節上。

也就是只有(c1+1)%h==c2才從c1向c2連邊表示選了c1必須選c2!c2向c1也是一樣。

然後縮個點找無出度的最小的點就行了。

邊註意開成兩倍——一組c也可能連兩條邊,%2之類的。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int
N=1e5+5; int n,m,h,a[N],hd[N],xnt,dfn[N],low[N],tim; int stack[N],top,cnt,col[N],siz[N],cd[N],ans=0x3f3f3f3f,prn; bool ins[N]; struct Ed{ int nxt,fr,to; Ed(int n=0,int f=0,int t=0):nxt(n),fr(f),to(t) {} }ed[N<<1];//!!!有可能(%2,一個c連兩條邊) void add(int x,int y) { ed[++xnt]=Ed(hd[x],x,y);hd[x]=xnt; }
void tarjan(int cr,int f) { dfn[cr]=low[cr]=++tim; stack[++top]=cr;ins[cr]=1; for(int i=hd[cr],v;i;i=ed[i].nxt) if(ins[v=ed[i].to])low[cr]=min(low[cr],dfn[v]);//directed edge,don‘t worry fa else if(!dfn[v])tarjan(v,cr),low[cr]=min(low[cr],low[v]); if(dfn[cr]==low[cr]) { cnt++;
while(stack[top]!=cr)col[stack[top]]=cnt,ins[stack[top--]]=0,siz[cnt]++; top--;col[cr]=cnt;ins[cr]=0;siz[cnt]++; } } int main() { scanf("%d%d%d",&n,&m,&h); for(int i=1;i<=n;i++)scanf("%d",&a[i]); int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); if((a[x]+1)%h==a[y])add(x,y);if((a[y]+1)%h==a[x])add(y,x); } for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0); for(int i=1,v;i<=xnt;i++) if((v=col[ed[i].fr])!=col[ed[i].to])cd[v]++; for(int i=1;i<=cnt;i++) if(!cd[i]&&siz[i]<ans)ans=siz[i],prn=i; printf("%d\n",ans); for(int i=1;i<=n;i++) if(col[i]==prn)printf("%d ",i); return 0; }

CF 949C Data Center Maintenance——思路+SCC