题目传送门
Boonie and Clyde
As two icons of the Great Depression, Bonnie and Clyde represent the ultimate criminal couple. Stories were written, headlines captured, and films were made about the two bank robbers known as Romeo and Juliet in a getaway car.
The new generation of Bonnie and Clyde is no longer cold-blooded killers with guns. Due to the boom of internet, they turn to online banks and scheme to hack the safety system. The safety system consists of a number of computers connected by bidirectional cables. Since time is limited, they decide that they will attack exactly two computers A and B in the network, and as a result, other computers won’t be able to transmit messages via A and B . The attack is considered successful if there are at least two computers (other than A and B ) that disconnected after the attack.
As they want to minimize the risk of being captured, they need to find the easiest way to destroy the safety system. However, a brief study of the network indicates that there are many ways to achieve their objective; therefore they kidnapped the computer expert, you, to help with the calculation. To simplify the problem, you are only asked to tell them how many ways there are to destroy the safety system.
Input
There are multiple test cases in the input file. Each test case starts with two integers N (3<=N<=1000) and M (0<=M<=10000) , followed by M lines describing the connections between the N computers. Each line contains two integers A , B (1<=A, B<=N) , which indicates that computer A and B are connected by a bidirectional cable.
There is a blank line between two successive test cases. A single line with N = 0 and M = 0 indicates the end of input file.
Output
For each test case, output one integer number representing the ways to destroy the safety system in the format as indicated in the sample output.
Sample Input
4 4
1 2
2 3
3 4
4 1
7 9
1 2
1 3
2 3
3 4
3 5
4 5
5 6
5 7
6 7
0 0
Sample Output
Case 1: 2
Case 2: 11
给定一张图,删除两个点后使得至少有两个以上的连通分量或者说剩下的点不连通,问有多少种方案数可以满足这个要求。
自己的思路:刚开始想了很久,就是差一点细节没改出来。刚开始就是分开讨论图的情况
正确姿势:直接先枚举删除一个点,再跑Tarjan求割点顺便计算每个连通分量中有几个点,和连通分量数目(Tarjan跑的次数)。
4. 如果有至少有3个连通分量,sum += n - 1; //除去删除的1号点
5. 如果只有一个连通分量,sum += cut[i]。也就是在确定这些点不连接1号点时,删除一个割点就能满足条件
6. 如果有2个连通分量,那就需要做连通分量内部点数的分析。如果两个连通分量内部点数都是1,也就是总共3个点的情况是不满足条件的sum += 0。如果有一个连通分量是1,一个大于1那么1那个连通分量不能删,只能从大于1的那个连通分量里面删,sum += n - 2(除去枚举的1号点和单独1个点的连通分量),如果两个连通分量的点数都大于1,也是随便删,sum += n-1。
最后别忘了答案要/2,因为先删和后删是同一种情况~
#include
#include
#include
#include
#include
#pragma warning(disable:4996)
using namespace std;
const int maxn = 1005;
vector<int>e[maxn];
int dfn[maxn];
int low[maxn];
bool cut[maxn];
int num,cnt; //num统计连通分量点数,cnt时间序
int vis,root; //vis为枚举的删除点,root为当前搜索树的根节点
inline void clear_set()
{
cnt = 0;
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(cut,false,sizeof(cut));
}
inline void tarjan(int x,int fx)
{
dfn[x] = low[x] = ++cnt;
num++;
int son = 0;
for(int i = 0;i < e[x].size();i++){
int y = e[x][i];
if(y == fx || y == vis) continue; //不能走删除的一号点和父节点
if(!dfn[y]){
son++;
tarjan(y,x);
low[x] = min(low[x],low[y]);
if((x == root && son > 1) || (low[y] >= dfn[x] && x != root)){
//判割点
cut[x] = true;
}
}
else if(dfn[y] < dfn[x]){
low[x] = min(low[x],dfn[y]);
}
}
}
int main()
{
int n,m,k = 1;
while(~scanf("%d%d",&n,&m)){
if(n == 0 && m == 0) break;
for(int i = 0;i <= n+1;i++){
e[i].clear();
}
for(int i = 0;i < m;i++){
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
int sum = 0;
for(vis = 1;vis <= n;vis++){
clear_set();
int ans = 0; //记录连通分量数目
int x = -1,y = -1;
for(int i = 1;i <= n;i++){
if(vis != i && !dfn[i]){
root = i;
ans++;
num = 0;
tarjan(i,-1);
if(x == -1) x = num;
else y = num;
}
}
if(ans == 1){
//只有一个连通分量的情况下
for(int i = 1;i <= n;i++){
sum += cut[i];
}
}
else if(ans == 2){
//两个连通分量
if(x == 1 && y == 1){
continue;
}
else if(x == 1 || y == 1){
sum += n-2;
}
else{
sum += n-1;
}
}
if(ans > 2){
//连通分量过多,随便删
sum += n-1;
}
}
printf("Case %d: %d\n",k++,sum/2);
}
return 0;
}
愿你走出半生,归来仍是少年~