https://www.lydsy.com/JudgeOnline/problem.php?id=2730
我真的快要被这东西搞死了…
状态差+图论内容渣 我从下午到晚上就只打了这一个东西…
可以说效率极差无比了
这道题分类讨论下
如果一个点双内只有一个割点,也就是叶子节点,那一定要在非割点的地方新建一个出口,不然割点毁了就无路可走了
如果一个点双内有两个及以上的割点 那么就不用新建出口,因为一个割点被毁了一定可以从另一个割点到叶子节点
如果一个点双内没有割点,那么就一定要新建两个出口,因为一个出口炸了就出不去了,大概这样,很简单的东西打了半天
可以不用直接求点双而是求出割点,只要遍历的时候不跨过割点就一定能遍历完这个点双。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e3 + 10;
int to[N], head[N], nxt[N], e;
int low[N], dfn[N], vis[N], cnt;
int cut[N], num, color, be[N];
int Cut, notCut;
void add(int x, int y) {
to[++ e] = y; nxt[e] = head[x]; head[x] = e;
}
void dfs(int x, int fa) {
int sz = 0;
dfn[x] = low[x] = ++ cnt;
for(int i = head[x]; i; i = nxt[i]) {
if(!dfn[to[i]]) {
++ sz;
dfs(to[i], x);
low[x] = min(low[x], low[to[i]]);
if((!fa && sz > 1) || (fa && low[to[i]] >= dfn[x]))
cut[x] = 1;
}
else if(to[i] != fa)
low[x] = min(low[x], dfn[to[i]]);
}
}
void find(int x) {
++ notCut, be[x] = color;
for(int i = head[x]; i; i = nxt[i]) {
if(cut[to[i]] && be[to[i]] != color) {
be[to[i]] = color;
++ Cut;
}
else if(!be[to[i]]) {
find(to[i]);
}
}
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("3225.in", "r", stdin);
freopen("3225.out", "w", stdout);
#endif
int cas = 1;
while(true) {
int n, m, x, y, ans1 = 0, ans2 = 1;
scanf("%lld", &m);
if(!m) break;
memset(head, 0, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(dfn, 0, sizeof(dfn));
memset(cut, 0, sizeof(cut));
memset(be, 0, sizeof(be));
e = cnt = n = color = 0;
for(int i = 1; i <= m; ++ i) {
scanf("%lld%lld", &x, &y);
add(x, y), add(y, x);
vis[x] = vis[y] = 1;
n = max(n, max(x, y));
}
for(int i = 1; i <= n; ++ i)
if(!dfn[i] && vis[i])
dfs(i, 0);
for(int i = 1; i <= n; ++ i)
if(vis[i] && !cut[i] && !be[i]) {
be[i] = ++ color;
Cut = notCut = 0;
find(i);
if(Cut == 0) {
ans1 += 2;
ans2 *= notCut * (notCut - 1) / 2;
}
if(Cut == 1) {
++ ans1;
ans2 *= notCut;
}
}
printf("Case %lld: %lld %lld\n", cas ++, ans1, ans2);
}
return 0;
}