传送门:http://codeforces.com/contest/950/problem/E
题目大意:
一个公司有n个数据站,m条信息,每条信息都需要放在2个数据站里。每天有h个小时,每个数据站都在某一个小时需要维护,维护的时候无法获得其中的信息。
该公司希望在保证一天的任意时候都能获得每条信息的情况下,将某些数据站的维护时间延后一小时。
给出的数据保证在更改前能在一天的任意时候都能获得每条信息,问最少需要延后多少个(至少一个)。
思路:
每个数据站都作为一个点,如果A、B有保存同一条信息并且A延后一小时会和B相同(即此时不能得到这条信息),A发生变化会影响B,则添加一条有向边(A,B)。
对建成的图利用Tarjan算法来得到其中的强连通分量(互相影响的几个站),之后对于每个强连通分量,统计它的出度,若出度不为0则代表着这个强连通分量发生变化会影响该强连通分量以外的点。
选出强连通分量点最少并且出度为0的强连通分量,即为答案。
AC代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cstdlib> #include<utility> #include<algorithm> #include<utility> #include<queue> #include<vector> #include<set> #include<stack> #include<cmath> #include<map> #define P pair<int,int> #define ll long long #define INF 100000000 #define M 1e9+7 #define MAX 500010 #define lson id*2,l,mid #define rson id*2+1,mid+1,r using namespace std; vector<int> e[MAX]; int n, m, h, a, b, no_sc, tot; int t[MAX]; int dfn[MAX], low[MAX], num[MAX], scc[MAX], out[MAX]; stack <int> s; void tarjan(int u) { dfn[u] = low[u] = ++tot; s.push(u); for (int i : e[u]) { if (dfn[i] == 0) { tarjan(i); low[u] = min(low[u], low[i]); } else if (scc[i] == 0) low[u] = min(low[u], dfn[i]); } if (dfn[u] == low[u]) { no_sc++; while (1) { int x = s.top(); s.pop(); scc[x] = no_sc; num[no_sc]++; if (x == u) break; } } } int main() { no_sc = 0; tot = 0; cin >> n >> m >> h; for (int i = 1; i <= n; i++) cin >> t[i]; for (int i = 1; i <= m; i++) { cin >> a >> b; if ((t[a] + 1) % h == t[b]) e[a].push_back(b); if ((t[b] + 1) % h == t[a]) e[b].push_back(a); } for (int i = 1; i <= n; i++) if (dfn[i] == 0) tarjan(i); for (int i = 1; i <= n; i++) { for (int j : e[i]) { if (scc[i] != scc[j]) out[scc[i]]++; } } int ans = 100010, flag; for (int i = 1; i <= no_sc; i++) { if (num[i] < ans&&out[i] == 0) { ans = num[i]; flag = i; } } cout << ans << endl; for (int i = 1; i <= n; i++) if (scc[i] == flag) cout << i << ' '; cout << endl; return 0; }