BZOJ2438: [中山市选2011]杀人游戏(tarjan)
题意
Sol
这题挺考验阅读理解能力的。。
如果能读懂的话,不难发现这就是在统计有多少入度为\(0\)的点
缩点后判断一下即可
当然有一种例外情况是\(1 -> 3, 2 -> 3\),也就是存在一个孤立点,判掉即可
判断的时候应当满足三个条件:所在联通块大小为\(2\),入度为0,所有指向的点入度均大于\(2\)
另外就是题目中没有说有没有重边,我没判过了,但是最好还是判一下。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 10;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, M;
vector<int> v[MAXN];//let's have a test
int dfn[MAXN], low[MAXN], vis[MAXN], tot, col[MAXN], cn, inder[MAXN], ans, siz[MAXN], flag[MAXN];
stack<int> s;
void tarjan(int x) {
dfn[x] = low[x] = ++tot; vis[x] = 1; s.push(x);
vector<int> *e = &v[x];
for(int i = 0, to; i < e -> size(); i++) {
if(!dfn[to = (*e)[i]]) tarjan(to), low[x] = min(low[x], low[to]);
else if(vis[to]) low[x] = min(low[x], dfn[to]);
}
if(low[x] == dfn[x]) {
int h; ++cn;
do {
h = s.top(); s.pop(); vis[h] = 0; col[h] = cn; siz[cn]++;
}while(h != x);
}
}
void rebuild() {
for(int i = 1; i <= N; i++) {
vector<int> *e = &v[i];
for(int j = 0, to; j < e -> size(); j++)
if(col[i] != col[to = (*e)[j]])
inder[col[to]]++;
}
for(int i = 1; i <= cn; i++) if(!inder[i]) ans++;
}
int main() {
N = read(); M = read();
for(int i = 1; i <= M; i++) {
int x = read(), y = read();
v[x].push_back(y);
}
for(int i = 1; i <= N; i++) if(!dfn[i]) tarjan(i);
rebuild();
for(int i = 1; i <= N; i++) {
if((!inder[col[i]]) && siz[col[i]] == 1) {
bool flag = 0; vector<int> *e = &v[i];
for(int j = 0, to; j < e -> size(); j++) {
if(inder[col[to = (*e)[j]]] == 1)
{flag = 1; break;}
}
if(flag == 0) {printf("%.6lf", 1 - (double) (ans - 1) / N); return 0;}
}
}
printf("%.6lf", 1 - (double) ans / N);
return 0;
}
/*
7 8
4 5
5 4
4 2
1 2
1 3
6 3
6 7
7 6
*/
作者:自为风月马前卒
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。