1. 程式人生 > >CF 949C Data Center Maintenance_強聯通分量_思維題

CF 949C Data Center Maintenance_強聯通分量_思維題

題意: 某土豪公司建立了n個數據中心,把m份資料每份在其中的兩個資料中心備份。 每個資料中心在一天h個小時當中有一個小時需要維護,此時不提供資料下載服務。 現在土豪公司想要將其中若干個資料中心的維護時間向後推遲一小時,並要求一天中任意時刻每份資料都可以被下載,問最少選取多少個數據中心維護。

題解: 首先,對於兩個備份的地方,我們發現只有 (C[a]+1)(C[a]+1) % h==C[b]h==C[b] 時,a,ba,b 兩個處理器需要同時後延一小時。於是,建圖的條件就是隻要 (C[a]+1)(C[a]+1) % h==C[b])h==C[b])

就在 (a,b)(a,b) 之間連一條邊,跑一遍 tarjantarjan 求出出度為 00 的大小最小的團即可。

Code:

#include<cstdio>
#include<algorithm>
#include<stack>
#include<vector>
using namespace std;
const int maxn = 1000000 + 5;
int n,m, h, C[maxn];
int head[maxn], to[maxn << 1], nex[maxn << 1],
cnt, degree[maxn]; int dfn[maxn], low[maxn], scc, siz[maxn], idx, vis[maxn], answer[maxn], ans; stack<int>S; inline void get_min(int &a, int b){ if(a > b) a = b;} struct Graph{ inline void add_edge(int u,int v){ nex[++cnt] = head[u]; head[u] = cnt; to[cnt] =
v; } void tarjan(int u){ low[u] = dfn[u] = ++scc; S.push(u); vis[u] = 1; for(int v = head[u]; v ; v = nex[v]) { if(!vis[to[v]]) { tarjan(to[v]); low[u] = min(low[u], low[to[v]]); } else if(!answer[to[v]]) get_min(low[u], dfn[to[v]]); } if(dfn[u] == low[u]) { ++idx; for(;;) { int x = S.top(); S.pop(); answer[x] = idx; ++siz[idx]; if(u == x) break; } } } inline void solve(){ siz[0] = maxn; for(int i = 1;i <= n; ++i) if(!vis[i]) tarjan(i); for(int i = 1;i <= n; ++i) { for(int j = head[i]; j ; j = nex[j]) { if(answer[to[j]] != answer[i]) ++degree[answer[i]]; } } for(int i = 1;i <= idx; ++i){ if(degree[i]) continue; if(siz[ans] > siz[i]) ans = i; } printf("%d\n", siz[ans]); for(int i = 1;i <= n; ++i) { if(answer[i] == ans) printf("%d ",i); } printf("\n"); } }T; int main() { scanf("%d%d%d",&n,&m,&h); for(int i = 1;i <= n; ++i) scanf("%d",&C[i]); while(m--){ int a,b; scanf("%d%d",&a,&b); if(((C[a] + 1) % h) == C[b]) T.add_edge(a, b); if(((C[b] + 1) % h) == C[a]) T.add_edge(b, a); } T.solve(); return 0; }