Codeforces 950E Data Center Maintenance Tarjan

题目链接:Data Center Maintenance

题意

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

输入

第一行为 3 个整数 n , m , h   ( 2 n 10 5 , 1 m 10 5 , 2 h 10 5 ) ,第二行为 n 个整数 u 1 , u 2 , , u n   ( 0 u i < h ) 表示第 i 个银行一天内需要维护的时间点。接下去 m 行每行两个整数 c i , 1 , c i , 2   ( 1 c i , 1 , c i , 2 n ) ,表示第 i 个客户把资料存放在第 c i , 1 和第 c i , 2 个银行。数据保证最初每一个客户都可以在一天的任意时刻取得资料。

输出

第一行为一个整数 k   ( 1 k n ) ,表示最少可以进行实验的银行数量,第二行为 k 个整数 x 1 , x 2 , , x k   ( 1 x i n ) ,表示 k 个进行实验的银行编号,如果有多解,输出任意一个。

样例

输入
3 3 5
4 4 0
1 3
3 2
3 1
输出
1
3
输入
4 5 4
2 1 0 3
4 3
3 2
1 2
1 4
1 3
输出
4
1 2 3 4

题解

如果某个客户将他的资料放在两个维护时间相邻的银行,第一个银行的维护时间 u i 和第二个银行的维护时间 u j 的关系为 ( u i + 1 ) % h = u j ,那么第一个银行一旦进行实验,第二个银行也需要进行实验,否则两个银行的维护时间就会相同,于是我们将所有客户存放资料的两个银行,如果满足上面的条件,就从第一个银行连一条有向边到第二个银行,表示如果前一个银行开始了维护,那么后面的银行同时也需要进行维护。如果这张有向图是一个 D A G ,那么只需要维护被指向的最后一个银行即可,如果有向图上存在环,就对有向图进行 T a r j a n 缩点成一个 D A G ,然后找到出度为 0 的点中点数最少的环。

过题代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <algorithm>
#include <functional>
#include <iomanip>
using namespace std;

#define LL long long
const int maxn = 100000 + 100;
int n, m, h, v, u, ans_cnt;
int ans[maxn];
int num[maxn];
int top, bcnt, dcnt;
int sta[maxn], dfn[maxn], low[maxn], belong[maxn], deg[maxn];
bool ins[maxn];
int cnt[maxn];
vector<int> G[maxn];
vector<int> GG[maxn];

void dfs(int x) {
    dfn[x] = low[x] = ++dcnt;
    ins[x] = true;
    sta[top++] = x;
    int len = G[x].size();
    for(int i = 0; i < len; ++i) {
        int pos = G[x][i];
        if(dfn[pos] == 0) {
            dfs(pos);
            low[x] = min(low[x], low[pos]);
        } else if(ins[pos]) {
            low[x] = min(low[x], dfn[pos]);
        }
    }
    if(dfn[x] == low[x]) {
        ++bcnt;
        int pos;
        do {
            pos = sta[--top];
            ins[pos] = false;
            belong[pos] = bcnt;
            ++cnt[bcnt];
        } while(pos != x);
    }
}

void Tarjan() {
    bcnt = top = dcnt = 0;
    memset(cnt, 0, sizeof(cnt));
    memset(deg, 0, sizeof(deg));
    memset(dfn, 0, sizeof(dfn));
    memset(ins, 0, sizeof(ins));
    for(int i = 1; i <= n; ++i) {
        if(dfn[i] == 0) {
            dfs(i);
        }
    }
    for(int i = 1; i <= bcnt; ++i) {
        GG[i].clear();
    }
    for(int i = 1; i <= n; ++i) {
        int len = G[i].size();
        for(int j = 0; j < len; ++j) {
            int pos = G[i][j];
            int u = belong[i];
            int v = belong[pos];
            if(u != v) {
                GG[u].push_back(v);
                ++deg[u];
            }
        }
    }
}

int main() {
    #ifdef LOCAL
        freopen("test.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    #endif // LOCAL
    ios::sync_with_stdio(false);

    while(scanf("%d%d%d", &n, &m, &h) != EOF) {
        ans_cnt = 0;
        for(int i = 1; i <= n; ++i) {
            G[i].clear();
        }
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &num[i]);
        }
        for(int i = 0; i < m; ++i) {
            scanf("%d%d", &u, &v);
            if((num[u] + 1) % h == num[v]) {
                G[u].push_back(v);
            }
            if((num[v] + 1) % h == num[u]) {
                G[v].push_back(u);
            }
        }
        Tarjan();
        int Min = INT_MAX;
        int Index;
        for(int i = 1; i <= bcnt; ++i) {
            if(deg[i] == 0 && cnt[i] < Min) {
                Min = cnt[i];
                Index = i;
            }
        }
        for(int i = 1; i <= n; ++i) {
            if(belong[i] == Index) {
                ans[ans_cnt++] = i;
            }
        }
        printf("%d\n", ans_cnt);
        for(int i = 0; i < ans_cnt; ++i) {
            if(i != 0) {
                printf(" ");
            }
            printf("%d", ans[i]);
        }
        printf("\n");
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/CSDNjiangshan/article/details/81389016