题目链接:Data Center Maintenance
题意
有 个银行, 个客户,每个客户都把自己的资料放在 个银行,一天总共有 小时,每个银行每天都要维护一小时,这一小时内银行无法工作,但是这一小时客户仍然可以在另一个银行提取资料,于是客户就可以一天 小时随时提取资料。现在要选择 个银行进行实验,每个进行实验的银行,它每天的维护时间都推迟一小时,如果原来的维护时间是 时,进行实验后银行的维护时间就为 时。问最少选择几个银行(至少一个)进行实验,才能仍然保证每一个客户随时都能提取到资料。
输入
第一行为 个整数 ,第二行为 个整数 表示第 个银行一天内需要维护的时间点。接下去 行每行两个整数 ,表示第 个客户把资料存放在第 和第 个银行。数据保证最初每一个客户都可以在一天的任意时刻取得资料。
输出
第一行为一个整数 ,表示最少可以进行实验的银行数量,第二行为 个整数 ,表示 个进行实验的银行编号,如果有多解,输出任意一个。
样例
输入 |
---|
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 |
题解
如果某个客户将他的资料放在两个维护时间相邻的银行,第一个银行的维护时间 和第二个银行的维护时间 的关系为 ,那么第一个银行一旦进行实验,第二个银行也需要进行实验,否则两个银行的维护时间就会相同,于是我们将所有客户存放资料的两个银行,如果满足上面的条件,就从第一个银行连一条有向边到第二个银行,表示如果前一个银行开始了维护,那么后面的银行同时也需要进行维护。如果这张有向图是一个 ,那么只需要维护被指向的最后一个银行即可,如果有向图上存在环,就对有向图进行 缩点成一个 ,然后找到出度为 的点中点数最少的环。
过题代码
#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;
}