Codeforces Round #469 (Div. 1) 949C C. Data Center Maintenance (Div. 2 950E)
题
OvO http://codeforces.com/contest/949/problem/C
codeforces 949C 950E
解
建图,记原图为 G1,缩点,记缩完点后的新图为G2
缩完点后的图 G2 必定无环,求这个无环图 G2 中每个点的入度,
找出入度为 0 的那些点,记这些点的集合为 S,然后把 S 中这些点映射到 G1 中,则这些点各自对应一个点集。S 的各点中,对应的最小集合即为所求集合
#include <iostream> #include <cstring> #include <cmath> #include <algorithm> #include <cstdio> #include <queue> #include <vector> #include <stack> using namespace std; const int N=100044; const int INF=1e9+44; struct data { int to,next; } tu[N*2]; struct sav { int a,b; } edgsav[N*2]; int head[N]; int ip; int dfn[N], low[N];///dfn[]表示深搜的步数,low[u]表示u或u的子树能够追溯到的最早的栈中节点的次序号 int sccno[N];///缩点数组,表示某个点对应的缩点值 int step; int scc_cnt;///强连通分量个数 int n,m,h,u[N]; int ind[N],outd[N]; int edgnum; void init() { ip=0; edgnum=0; memset(head,-1,sizeof(head)); memset(ind,0,sizeof(ind)); memset(outd,0,sizeof(outd)); } void add(int u,int v) { edgnum++,edgsav[edgnum].a=u,edgsav[edgnum].b=v; tu[ip].to=v,tu[ip].next=head[u],head[u]=ip++; } vector<int> scc[N];///得出来的缩点,scc[i]里面存i这个缩点具体缩了哪些点 stack<int> S; void dfs(int u) { dfn[u] = low[u] = ++step; S.push(u); for (int i = head[u]; i !=-1; i=tu[i].next) { int v = tu[i].to; if (!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if (!sccno[v]) low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { scc_cnt += 1; scc[scc_cnt].clear(); while(1) { int x = S.top(); S.pop(); if (sccno[x] != scc_cnt) scc[scc_cnt].push_back(x); sccno[x] = scc_cnt; if (x == u) break; } } } void tarjan(int n) { memset(sccno, 0, sizeof(sccno)); memset(dfn, 0, sizeof(dfn)); step = scc_cnt = 0; for (int i = 1; i <=n; i++) if (!dfn[i]) dfs(i); } inline int trans(int x) { return (x+1)%h; } int main() { int a,b; init(); scanf("%d%d%d",&n,&m,&h); for(int i=1;i<=n;i++) scanf("%d",&u[i]); for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); if(trans(u[a])==u[b]) add(a,b); if(trans(u[b])==u[a]) add(b,a); } tarjan(n); for(int i=1;i<=edgnum;i++) if(sccno[edgsav[i].a]!=sccno[edgsav[i].b]) { outd[sccno[edgsav[i].a]]++; ind[sccno[edgsav[i].b]]++; } int the,tmp=INF; for(int i=1;i<=scc_cnt;i++) if(outd[i]==0 && scc[i].size()<tmp) the=i,tmp=scc[i].size(); printf("%d\n",tmp); for(int i=0;i<scc[the].size();i++) { printf("%d",scc[the][i]); if(i==scc[the].size()-1) puts(""); else printf(" "); } return 0; }