首页 > 技术文章 > 【题解】 CF949C Data Center Maintenance

JCNL666 2019-04-23 10:05 原文

\(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;
}

推荐阅读