题意:
某土豪公司建立了n个数据中心,把m份资料每份在其中的两个数据中心备份。 每个数据中心在一天h个小时当中有一个小时需要维护,此时不提供资料下载服务。 现在土豪公司想要将其中若干个数据中心的维护时间向后推迟一小时,并要求一天中任意时刻每份资料都可以被下载,问最少选取多少个数据中心维护。
输入 第一行n,m,h,见题目描述 第二行n个整数,维护时间 接下来m行,每行两个整数,存相同资料的一对中心
输出 第一行 必须推迟数 第二行 分别是哪些中心
抽象成点后 用边表示冲突
和前几天做的一个 POI 题方法类似。我们考虑把数据中心抽象成点。对于一个客户的两组数据,如果维护时间相隔很久那么两个数据间不会有冲突,如果是相邻的,我们把时间轴在前面的点向后面的点连一条边。表示若选取这个点,则与所指向的点冲突。
如果图中出现了 强连通分量。则必须选取整个强连通分量,故缩点。
缩点后所建成新图是一个
DAG
D
A
G
有向无环图。我们只要选取没有出度中答案最优的点即可。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
struct edge{
int to,next;
}e[MAXN<<1],ec[MAXN<<1];
int head[MAXN],cnt=0,headc[MAXN],cnt2=0,indegree[MAXN];
inline void add(int u,int v){
e[++cnt]=(edge){v,head[u]},head[u]=cnt;
}
inline void addc(int u,int v){
ec[++cnt2]=(edge){v,headc[u]},headc[u]=cnt2,indegree[u]++;
}
int dfn[MAXN],low[MAXN],belong[MAXN],tot=0,colorsize[MAXN],tim=0;
int sta[MAXN],top=0;
bool insta[MAXN];
vector<int>vec[MAXN];
void tarjan(int u){
sta[++top]=u;
insta[u]=1;
dfn[u]=low[u]=++tim;
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(insta[v]&&dfn[v]<low[u])low[u]=dfn[v];
}
if(dfn[u]==low[u]){
int tem=0;++tot;
while(tem!=u){
tem=sta[top--];
vec[tot].push_back(tem);
insta[tem]=0;
belong[tem]=tot;
colorsize[tot]++;
}
}
}
int a[MAXN],n,m,h;
int main(){
scanf("%d%d%d",&n,&m,&h);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
if(a[x]>a[y])swap(x,y);
if(a[y]-a[x]==1)add(x,y);
if(a[x]==0&&(a[y]==h-1))add(y,x);
//if(abs(a[x]-a[y])==1||((a[x]==h-1)&&(!a[y])))add(x,y),cout<<x<<" sas "<<y<<endl;
}
for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
for(int u=1;u<=n;u++){
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(belong[v]!=belong[u])addc(belong[u],belong[v]);
}
}
int ans=2e9,which;
for(int i=1;i<=tot;i++){
if(!indegree[i]){
if(colorsize[i]<ans)ans=colorsize[i],which=i;
}
}
printf("%d\n",ans);
for(int i=0;i<vec[which].size();i++){
printf("%d ",vec[which][i]);
}
return 0;
}