题意:
某土豪公司建立了n个数据中心,把m份资料每份在其中的两个数据中心备份。 每个数据中心在一天h个小时当中有一个小时需要维护,此时不提供资料下载服务。 现在土豪公司想要将其中若干个数据中心的维护时间向后推迟一小时,并要求一天中任意时刻每份资料都可以被下载,问最少选取多少个数据中心维护。
题解:
首先,对于两个备份的地方,我们发现只有 % 时, 两个处理器需要同时后延一小时。于是,建图的条件就是只要 % 就在 之间连一条边,跑一遍 求出出度为 的大小最小的团即可。
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
", siz[ans]);
for(int i = 1;i <= n; ++i)
{
if(answer[i] == ans) printf("%d ",i);
}
printf("
");
}
}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;
}