Codeforces 949C(Data Center Maintenance,Tarjan缩点)

难度系数:1900 graphs

题意:有 n 个银行,m 个客户,每个客户都把自己的资料放在 2 个银行,一天总共有 h 小时,每个银行每天都要维护一小时,这一小时内银行无法工作,但是这一小时客户仍然可以在另一个银行提取资料,于是客户就可以一天 h 小时随时提取资料。现在要选择 k 个银行进行实验,每个进行实验的银行,它每天的维护时间都推迟一小时,如果原来的维护时间是 h−1 时,进行实验后银行的维护时间就为 0 时。问最少选择几个银行(至少一个)进行实验,才能仍然保证每一个客户随时都能提取到资料。

 

输入:第一行为 3 个整数n,m,h (2≤n≤105,1≤m≤1e5,2≤h≤1e5),第二行为 nn 个整数 u1,u2,⋯,un (0≤ui<h)表示第 i 个银行一天内需要维护的时间点。接下去 m行每行两个整数 ci,1,ci,2 (1≤ci,1,ci,2≤n),表示第 i 个客户把资料存放在第 ci,1 和第 ci,2 个银行。数据保证最初每一个客户都可以在一天的任意时刻取得资料。

 

解法:其实想想也能知道转化成图论关系,但是怎么建边呢?我们可以知道如果(p[u]+1)%h==p[v],就能在u和v之间建立一个单向边,add(u,v);同样,如果(p[v]+1)%h==p[u],就能在v和u之间建立一个单向边,add(v,u)。记住建边的时候不要用 else if,因为有一组数据卡的条件是回路只有2个点...既然知道了建边的关系了,那么我们就可以利用Tarjan强联通的缩点方法把它缩成id[i],这个时候统计一下每个id[i]的outdeg有几个;我们寻找答案的方法是:1~n中,outdeg[id[i]]为0,且num[id[i]]最小。那么其实这个问题说到这个地步也算是比较简单了。感觉想想还是挺容易的,就是坑点有点多吧。。。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
#define mem(a,b) memset(a,b,sizeof(a))
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int maxn=1e5+5;
int tot,head[maxn];
struct E{
    int to,next;
}edge[maxn<<1];
void add(int u,int v){
    edge[tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot++;
}
int n,m,h,p[maxn],dfn[maxn],low[maxn],vis[maxn],id[maxn],num[maxn],tott,cnt=0;
stack<int> s;
void tarjan(int x){
    low[x]=dfn[x]=++tott;
    s.push(x);vis[x]=1;
    for(int i=head[x];i!=-1;i=edge[i].next){
        int v=edge[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(vis[v]){
            low[x]=min(low[x],dfn[v]);
        }
    }
    if(low[x]==dfn[x]){
        cnt++;
        while(1){
            int now=s.top();s.pop();
            vis[now]=0;
            id[now]=cnt;
            num[cnt]+=1;
            if(now==x) break;
        }
    }
}
int out[maxn];vector<int> G[maxn];
int main(){
    cin>>n>>m>>h;mem(head,-1);
    rep(i,1,n) cin>>p[i];
    while(m--){
        int u,v;cin>>u>>v;
        if((p[u]+1)%h==p[v]) add(u,v);
        if((p[v]+1)%h==p[u]) add(v,u);
    }
    rep(i,1,n){
        if(!dfn[i]) tarjan(i);
    }
    for(int i=1;i<=n;i++){
        for(int j=head[i];j!=-1;j=edge[j].next){
            if(id[i]!=id[edge[j].to]){
                G[id[i]].push_back(id[edge[j].to]);
                out[id[i]]+=1;
            }
        }
    }
    int ans=INF,cur;
    for(int i=1;i<=cnt;i++){
        if(out[i]==0){
            ans=min(ans,num[i]);
            if(num[i]==ans) cur=i;
        }
    }
    vector<int> vec;
    for(int i=1;i<=n;i++){
        if(id[i]==cur){
            vec.push_back(i);
        }
    }    
    cout<<ans<<endl;
    for(int i=0;i<vec.size();i++){
        cout<<vec[i]<<" ";
    }
    puts("");
}
View Code

 

 

posted @ 2020-05-16 12:14  Anonytt  阅读(163)  评论(0编辑  收藏  举报