HDU3671(Boonie and Clyde)

题目传送门
                     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

题意

给定一张图,删除两个点后使得至少有两个以上的连通分量或者说剩下的点不连通,问有多少种方案数可以满足这个要求。

思路

自己的思路:刚开始想了很久,就是差一点细节没改出来。刚开始就是分开讨论图的情况

  1. 如果最开始图就不连通有两个以上的连通分量那两个点岂不是随便删就可以?
  2. 如果只有一个连通分量的时候枚举割点,割点删完掉之后就保证有两个以上的连通分量,然后第二个点也是可以随便删。
  3. 如果是一个点双连通没有割点那就开始枚举删除一号点,在求割点枚举删掉割点。
    上面的做法90%是对的,但是有细节没有处理就是内部连通块数目是1的时候没有做判定,导致wa几发找不到错误。

正确姿势:直接先枚举删除一个点,再跑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 <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
#include <algorithm>
#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;
}

愿你走出半生,归来仍是少年~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值