HDU 3844
题目链接:
题意:
给一个图,保证连通。问至少修几个通往地上的通道,使得其中一个点坏掉的时候,其他点都有通道可以通向地面。
思路:
上来先想到应该是划分双连通分量,双连通分量缩点。
这是错的啊,这是错的啊,这是错的啊!只有边双连通分量才能缩点啊!
改成点双连通分量就行,然后再注意些小问题最后答案注意乘法不爆long long,比如n要清0。
源码:
邻接表版
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <stack>
#include <utility>
using namespace std;
typedef pair<int,int> pii;
#define LL long long
#define gmax(a,b) ((a) > (b) ? (a) : (b))
#define gmin(a,b) ((a) < (b) ? (a) : (b))
#define MAXN (200005)
vector<int>lin[MAXN], bcc[MAXN];
stack<pii>sta;
int up;
int n, m;
int pre[MAXN], low[MAXN], clock;
int bccno[MAXN], bcccnt;
int iscut[MAXN];
int first[MAXN];
LL cnt, ans;
void DFS_iscut(int u, int fa)
{
pre[u] = low[u] = ++clock;
int child = 0;
for(int i = 0 ; i < (int)lin[u].size() ; i++){
int v = lin[u][i];
if(pre[v] == 0){
sta.push(make_pair(u, v));
child++;
DFS_iscut(v, u);
low[u] = gmin(low[u], low[v]);
if(low[v] >= pre[u]){
iscut[u] = 1;
bcccnt++;
bcc[bcccnt].clear();
while(!sta.empty()){
pii p = sta.top(); sta.pop();
if(bccno[p.first] != bcccnt){
bccno[p.first] = bcccnt;
bcc[bcccnt].push_back(p.first);
}
if(bccno[p.second] != bcccnt){
bccno[p.second] = bcccnt;
bcc[bcccnt].push_back(p.second);
}
if(p.first == u && p.second == v)
break;
}
}
}
else if(v != fa){
if(pre[u] > pre[v]){
sta.push(make_pair(u, v));
low[u] = gmin(low[u], pre[v]);
}
}
}
if(fa < 0 && child <= 1)
iscut[u] = 0;
}
int main()
{
int cas = 0;
while(scanf("%d", &m) != EOF && m){
for(int i = 1 ; i <= m + 1 ; i++)
lin[i].clear();
int u, v;
n = 0;
memset(first, 0, sizeof(first));
for(int i = 1 ; i <= m ; i++){
scanf("%d%d", &u, &v);
n = gmax(n, u), n = gmax(n, v);
if(first[u] == 0) first[u] = 1, lin[u].clear();
lin[u].push_back(v);
if(first[v] == 0) first[v] = 1, lin[v].clear();
lin[v].push_back(u);
}
cnt = 0, ans = 1;
memset(pre, 0, sizeof(pre));
memset(bccno, 0, sizeof(bccno));
memset(iscut, 0, sizeof(iscut));
bcccnt = 0;
clock = 0;
while(!sta.empty()) sta.pop();
for(int i = 1 ; i <= n ; i++)
if(pre[i] == 0) DFS_iscut(i, -1);
if(bcccnt == 1){
cnt = 2;
LL z = n;
ans = z * (z - 1) / 2;
}
else{
cnt = 0;
ans = 1;
// printf("bcccnt = %d\n", bcccnt);
for(int i = 1 ; i <= bcccnt ; i++){
int tmark = 0;
// printf("i = %d bcc = ", i);
LL z = (int)bcc[i].size();
for(int j = 0 ; j < (int)bcc[i].size() ; j++){
// printf("%d ", bcc[i][j]);
if(iscut[bcc[i][j]]) tmark++;
}
// printf("\n");
// printf("tmark = %d\n", tmark);
// printf("\n");
if(tmark == 1){
cnt++;
ans *= (z - 1);
}
}
}
printf("Case %d: %I64d %I64d\n", ++cas, cnt, ans);
}
return 0;
}
前向星版(差不多好嘛)
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#include <stack>
#include <utility>
using namespace std;
typedef pair<int,int> pii;
#define LL long long
#define gmax(a,b) ((a) > (b) ? (a) : (b))
#define gmin(a,b) ((a) < (b) ? (a) : (b))
#define MAXN (100005)
vector<int>lin[MAXN], bcc[MAXN];
stack<pii>sta;
int up;
int n, m;
int pre[MAXN], low[MAXN], clock;
int bccno[MAXN], bcccnt;
int iscut[MAXN];
int head[MAXN];
struct Edge
{
int u, v, ne;
Edge(){}
Edge(int _u, int _v){u = _u, v = _v, ne = head[u];}
}edge[MAXN * 2];
int edge_cnt;
void addedge(int u, int v)
{
edge[edge_cnt] = Edge(u, v);
head[u] = edge_cnt++;
}
void DFS_iscut(int u, int fa)
{
pre[u] = low[u] = ++clock;
int child = 0;
for(int i = head[u] ; i != -1 ; i = edge[i].ne){
int v = edge[i].v;
if(pre[v] == 0){
sta.push(make_pair(u, v));
child++;
DFS_iscut(v, u);
low[u] = gmin(low[u], low[v]);
if(low[v] >= pre[u]){
iscut[u] = 1;
bcccnt++;
bcc[bcccnt].clear();
while(!sta.empty()){
pii p = sta.top(); sta.pop();
if(bccno[p.first] != bcccnt){
bccno[p.first] = bcccnt;
bcc[bcccnt].push_back(p.first);
}
if(bccno[p.second] != bcccnt){
bccno[p.second] = bcccnt;
bcc[bcccnt].push_back(p.second);
}
if(p.first == u && p.second == v)
break;
}
}
}
else if(v != fa){
if(pre[u] > pre[v]){
sta.push(make_pair(u, v));
low[u] = gmin(low[u], pre[v]);
}
}
}
if(fa < 0 && child <= 1)
iscut[u] = 0;
}
int main()
{
// freopen("data.txt", "r", stdin);
// freopen("data2.txt", "w", stdout);
int cas = 0;
while(scanf("%d", &m) != EOF && m){
for(int i = 1 ; i <= m + 1 ; i++)
lin[i].clear();
int u, v;
edge_cnt = 0;
n = 0;
memset(head, -1, sizeof(head));
for(int i = 1 ; i <= m ; i++){
scanf("%d%d", &u, &v);
n = gmax(n, u), n = gmax(n, v);
// if(first[u] == 0) first[u] = 1, lin[u].clear();
// lin[u].push_back(v);
// if(first[v] == 0) first[v] = 1, lin[v].clear();
// lin[v].push_back(u);
addedge(u, v);
addedge(v, u);
}
int cnt = 0;
LL ans = 1;
memset(pre, 0, sizeof(pre));
memset(bccno, 0, sizeof(bccno));
memset(iscut, 0, sizeof(iscut));
bcccnt = 0;
clock = 0;
while(!sta.empty()) sta.pop();
for(int i = 1 ; i <= n ; i++)
if(pre[i] == 0) DFS_iscut(i, -1);
// for(int i = 1 ; i <= bcccnt ; i ++){
// printf("bcccnt = %d\n", i);
// for(int j = 0 ; j < (int)bcc[i].size() ; j++)
// printf("%d ", bcc[i][j]);
// printf("\n");
// }
// printf("bcc\n");
if(bcccnt == 1){
cnt = 2;
LL z = n;
ans = z * (z - 1) / 2;
}
else{
for(int i = 1 ; i <= bcccnt ; i++){
int tmark = 0;
LL z = (int)bcc[i].size();
for(int j = 0 ; j < (int)bcc[i].size() ; j++){
if(iscut[bcc[i][j]]) tmark++;
}
if(tmark == 1){
cnt++;
ans *= (z - 1);
}
}
}
printf("Case %d: %d %I64d\n", ++cas, cnt, ans);
}
return 0;
}