【题解】 CF949C Data Center Maintenance

本文探讨了一种在有限时间内对维护关键信息的机器进行最优调度的算法。通过构建有向图和使用Tarjan算法找到强联通分量,该算法确定了最小数量的机器推迟维护,以确保任何时候都能获取所有信息。代码实现展示了如何找到出度最小的节点,以及在强联通分量中选择节点最少的块。

\(Description:\)

给出 \(n\) 台机子,每台机子有一个信息,每个信息由两台机子维护,现在要在 \(h\) 小时内对一些机子进行维护,维护时长一小时,现在要求所有时刻都可以取出任何信息,求做少要推迟那些中心,如果时间等于 \(h\) 变为 \(0\)

\(Sample\) \(Input:\)

3 3 5
4 4 0
1 3
3 2
3 1

\(Sample\) $Output: $

1
3

\(Solution:\)

考虑其实如果两个机子的维修时间 满足

\(t[c_1]+1 \equiv t[c_2] \pmod {h}\)

说明这个时候我们如果推迟 \(c_1\)

那么也得推迟 \(c_2\)

反一反同理,但是这有什么用呢?

考虑我们对于要求同时推迟的两台连一条有向边,这样可以构成一张图。

那么这张图上如果选一个点,那么所有他连出去的点都要延迟,那么很明显,只要出度最小就是最优的。

但是发现这个图可能会有强联通分量,那么就缩个点,发现这个强联通分量里的点都是必须同时推迟。

那么再选出度最小的前提下,我们那也得要求这个块的点个数最小。

#include<bits/stdc++.h>
using namespace std;
int n,m,h,ans,cnt,num,Min,En,sum;
const int N=1e5+5;
int head[N],deg[N],t[N],scc[N],c[N][2];
int size[N],ins[N],dfn[N],low[N];
vector <int> tt[N];
stack <int> s;
struct edge {
    int next,to;
}E[N<<1];
inline void add(int from,int to){
    E[++En].next=head[from];
    E[En].to=to;
    head[from]=En;
}
inline void tarjan(int u){
    ins[u]=1; s.push(u);
    dfn[u]=low[u]=++num;
    for(int i=head[u];i;i=E[i].next){
        int v=E[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(ins[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        scc[u]=++cnt;
        ins[u]=0;
        tt[cnt].push_back(u);
        while(s.top()!=u){
            int v=s.top();
            ins[v]=0;
            scc[v]=cnt;
            tt[cnt].push_back(v);
            s.pop();
        }
        s.pop();
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&h);
    for(int i=1;i<=n;++i) scanf("%d",&t[i]);
    for(int i=1;i<=m;++i){
        scanf("%d%d",&c[i][0],&c[i][1]);
        if((t[c[i][0]]+1)%h==t[c[i][1]]%h) add(c[i][0],c[i][1]);
        if((t[c[i][1]]+1)%h==t[c[i][0]]%h) add(c[i][1],c[i][0]);
    }
    for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
    for(int i=1;i<=m;++i){
        if(scc[c[i][0]]==scc[c[i][1]]) continue;
        if((t[c[i][0]]+1)%h==t[c[i][1]]%h) deg[scc[c[i][0]]]++;
        if((t[c[i][1]]+1)%h==t[c[i][0]]%h) deg[scc[c[i][1]]]++;
    }
    Min=ans=0x3f3f3f3f;
    for(int i=1;i<=cnt;++i) Min=min(deg[i],Min);
    for(int i=1;i<=cnt;++i) 
        if(Min==deg[i] && (int)tt[i].size()<ans)
            ans=tt[i].size(),sum=i;
    printf("%d\n",ans);
    for(int i=0;i<(int)tt[sum].size();++i)
        printf("%d ",tt[sum][i]);
    putchar('\n');
    return 0;
}

转载于:https://www.cnblogs.com/JCNL666/p/10754724.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值