卧薪尝胆,厚积薄发。
Data Center Maintenance
Date: Sun Jul 08 21:43:02 CST 2018 In Category: NoCategory

Description:

有 $n$ 个信息中心,第 $i$ 个信息中心要在第 $t_i$ 个小时维护,维护期间信息不能被获得。
每个用户的数据都有两份备份,第 $i$ 个用户的数据放在信息中心 $c_{i,1}$ 和 $c_{i,2}$ 。
现在要挑选一个尽量小的信息中心集合,使得将这个集合的维护时间推迟一个小时后,仍然能保证每个用户的数据在任意时刻都能获得。
$2\le n \le10^5$

Solution:

如果 $t_{c_{i,1}}+1=t_{c_{i,2}}$ 则连边 $c_{i,1}\to c_{i,2}$ ,代表如果推迟 $c_{i,1}$ 则必须推迟 $c_{i,2}$ ,反之亦然,这样求出出度为 $0$ 的最小的 $SCC$ 即为答案。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<stack>
#include<cstring>
using namespace std;
int n,m,h;
#define MAXN 100010
int t[MAXN];
struct edge
{
int to,nxt;
}e[MAXN << 2];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b)
{
++edgenum;e[edgenum].to = b;e[edgenum].nxt = lin[a];lin[a] = edgenum;
return;
}
stack<int> s;
int dfn[MAXN],low[MAXN],tot = 0;
bool v[MAXN];
int ins[MAXN],siz[MAXN];
int scc = 0;
void tarjan(int k)
{
dfn[k] = low[k] = ++tot;
s.push(k);v[k] = true;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(dfn[e[i].to] == 0)
{
tarjan(e[i].to);
low[k] = min(low[k],low[e[i].to]);
}
else if(v[e[i].to])
{
low[k] = min(low[k],dfn[e[i].to]);
}
}
if(low[k] >= dfn[k])
{
int t;
++scc;
do
{
t = s.top();s.pop();
v[t] = false;ins[t] = scc;
siz[scc]++;
}while(t != k);
}
return;
}
int deg[MAXN];
int main()
{
scanf("%d%d%d",&n,&m,&h);
for(int i = 1;i <= n;++i)
{
scanf("%d",&t[i]);
}
int c1,c2;
for(int i = 1;i <= m;++i)
{
scanf("%d%d",&c1,&c2);
if((t[c1] + 1) % h == t[c2])add(c1,c2);
if((t[c2] + 1) % h == t[c1])add(c2,c1);
}
for(int i = 1;i <= n;++i)
{
if(dfn[i] == 0)
{
tarjan(i);
}
}
memset(deg,0,sizeof(deg));
for(int k = 1;k <= n;++k)
{
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(ins[k] != ins[e[i].to])
{
++deg[ins[k]];
}
}
}
int ans = -1;
for(int i = 1;i <= scc;++i)
{
if(deg[i] == 0)
{
if(ans == -1 || siz[i] < siz[ans])
{
ans = i;
}
}
}
cout << siz[ans] << endl;
for(int i = 1;i <= n;++i)
{
if(ins[i] == ans)
{
printf("%d ",i);
}
}
puts("");
return 0;
}
In tag: 图论-tarjan
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡