/*
从一个图当中去掉两个节点使得图不联通的方法有多少种
首先枚举去掉的第一个点,去掉第一个点之后
1. 图已经不连通且分为两块:
a.这两块各含一个节点,此时无法通过再去掉一个点使图不连通;
b.其中一块只含一个节点,另一块有多个节点,此时从含多个结点的块中任取一个搭配去掉的第一个节点,
共有n - 2 种;
c.这两块各含多个节点,则从剩下节点中取出任何一个与去掉的第一个节点搭配,共有n - 2种方法;
2.图已经不连通且分为三块及以上:
从剩下节点中任取一个,共有n - 1种;
3.图依旧联通:
从剩下的点中找割点,方法数加上割点的个数;
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
const int maxn = 1000 + 5;
const int inf = 1000000000;
int vis[maxn],pre[maxn],iscut[maxn];
int low[maxn],num,dfs_clock,cut,n,m;
int v[maxn];
vector<int>G[maxn];
void dfs_count(int u,int fa,int del)//求出去掉某一节点后连通块的个数,看网上标程发现下面求割点的dfs可以顺便求连通块数;
{
vis[u] = 1;
++num;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(vis[v] ||v == fa||v == del) continue;
dfs_count(v,u,del);
}
return ;
}
int dfs(int u,int fa,int del) //寻找割点
{
int lowu = pre[u] = ++dfs_clock;
int child = 0;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(v==del) continue;
if(!pre[v]){
++child;
int lowv = dfs(v,u,del);
lowu = min(lowu,lowv);
if(lowv >= pre[u]){
iscut[u] = 1;
}
}
else if(pre[v]<pre[u]&&v!=fa){
lowu = min(lowu,pre[v]);
}
}
if(fa<0&&child==1){
iscut[u] = 0;
}
low[u] = lowu;
return lowu;
}
int main()
{
//freopen("D:\\professional debugging\\in5.txt","r",stdin);
//freopen("D:\\professional debugging\\out52.txt","w",stdout);
int kase = 1;
while(scanf("%d %d",&n,&m)==2&&n){ //此题的m可以等于0,一开始&&n&&m就无奈wa了好多发
for(int i=0;i<=n;i++){
G[i].clear();
}
for(int i=0;i<m;i++){
int x,y;
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
int ans = 0;
for(int i=1;i<=n;i++){
int block = 0;
mem(vis,0); mem(v,0);
for(int j = 1;j<=n;j++){
if(i==j) continue;
if(!vis[j]){
num = 0;
dfs_count(j,-1,i);
v[++block] = num;
}
}
if(block==1){
mem(low,0); mem(pre,0); mem(iscut,0); dfs_clock = 0;
cut = 0;
if(i==1)
dfs(2,-1,1);
else
dfs(1,-1,i);
for(int k=1;k<=n;k++)
if(iscut[k]) ++cut;
ans += cut;
}
else if(block==2){
sort(v+1,v + 1 + block);
if(v[1]==1&&v[2]!=1)
ans += n-2;
else if(v[1]!=1&&v[2]!=1)
ans += n-1;
}
else{
ans += n-1;
}
}
ans /= 2;
printf("Case %d: %d\n",kase++,ans);
}
return 0;
}
从一个图当中去掉两个节点使得图不联通的方法有多少种
首先枚举去掉的第一个点,去掉第一个点之后
1. 图已经不连通且分为两块:
a.这两块各含一个节点,此时无法通过再去掉一个点使图不连通;
b.其中一块只含一个节点,另一块有多个节点,此时从含多个结点的块中任取一个搭配去掉的第一个节点,
共有n - 2 种;
c.这两块各含多个节点,则从剩下节点中取出任何一个与去掉的第一个节点搭配,共有n - 2种方法;
2.图已经不连通且分为三块及以上:
从剩下节点中任取一个,共有n - 1种;
3.图依旧联通:
从剩下的点中找割点,方法数加上割点的个数;
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
const int maxn = 1000 + 5;
const int inf = 1000000000;
int vis[maxn],pre[maxn],iscut[maxn];
int low[maxn],num,dfs_clock,cut,n,m;
int v[maxn];
vector<int>G[maxn];
void dfs_count(int u,int fa,int del)//求出去掉某一节点后连通块的个数,看网上标程发现下面求割点的dfs可以顺便求连通块数;
{
vis[u] = 1;
++num;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(vis[v] ||v == fa||v == del) continue;
dfs_count(v,u,del);
}
return ;
}
int dfs(int u,int fa,int del) //寻找割点
{
int lowu = pre[u] = ++dfs_clock;
int child = 0;
for(int i=0;i<G[u].size();i++){
int v = G[u][i];
if(v==del) continue;
if(!pre[v]){
++child;
int lowv = dfs(v,u,del);
lowu = min(lowu,lowv);
if(lowv >= pre[u]){
iscut[u] = 1;
}
}
else if(pre[v]<pre[u]&&v!=fa){
lowu = min(lowu,pre[v]);
}
}
if(fa<0&&child==1){
iscut[u] = 0;
}
low[u] = lowu;
return lowu;
}
int main()
{
//freopen("D:\\professional debugging\\in5.txt","r",stdin);
//freopen("D:\\professional debugging\\out52.txt","w",stdout);
int kase = 1;
while(scanf("%d %d",&n,&m)==2&&n){ //此题的m可以等于0,一开始&&n&&m就无奈wa了好多发
for(int i=0;i<=n;i++){
G[i].clear();
}
for(int i=0;i<m;i++){
int x,y;
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
int ans = 0;
for(int i=1;i<=n;i++){
int block = 0;
mem(vis,0); mem(v,0);
for(int j = 1;j<=n;j++){
if(i==j) continue;
if(!vis[j]){
num = 0;
dfs_count(j,-1,i);
v[++block] = num;
}
}
if(block==1){
mem(low,0); mem(pre,0); mem(iscut,0); dfs_clock = 0;
cut = 0;
if(i==1)
dfs(2,-1,1);
else
dfs(1,-1,i);
for(int k=1;k<=n;k++)
if(iscut[k]) ++cut;
ans += cut;
}
else if(block==2){
sort(v+1,v + 1 + block);
if(v[1]==1&&v[2]!=1)
ans += n-2;
else if(v[1]!=1&&v[2]!=1)
ans += n-1;
}
else{
ans += n-1;
}
}
ans /= 2;
printf("Case %d: %d\n",kase++,ans);
}
return 0;
}