1523 SPF + P1656 炸铁路 (求割点模板 + 求桥模板)

题目链接

问题描述:给你一张无向图,求出图中割点的数目和每个割点所能划分的图的联通分量的数目

思路:套用模板

如果u是割点,成立条件有两个;

第一:u是根,并且u的孩子数目大于1。

第二:u不是根,并且存在至少一个子树v,使得lowv >= pre[u]。

割点u所对应的联通分量的个数等于多少?分为两种情况;

第一:u是根,数目就等于son。

第二:u不是根,数目就等于满足lowv >= pre[u]的u孩子的个数 + 1。

根据上述的割点的性质,套用模板就可以求出这道题了:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cmath>
#include<vector>
#define pb push_back
using namespace std;
const int maxn = 1500;

int pre[maxn],cnt=0,iscut[maxn];
vector<int>G[maxn];
int dfs(int u,int fa)
{
	int lowu = pre[u] = ++cnt;
	int son = 0;
	for(int i=0;i<G[u].size();i++)
	{
		int v = G[u][i];
		if(!pre[v])
		{
			++son;
			int lowv = dfs(v,u);
			lowu = min(lowv,lowu);
			if(lowv >= pre[u])++iscut[u];
		}
		else if(pre[v] < pre[u] && v != fa)
		lowu = min(lowu,pre[v]);
	}
	if(fa<0 && son == 1)iscut[u] = 0;
	else if(fa > 0 && iscut[u])++iscut[u];
	return lowu;
}
int main()
{
	int u,v,kase = 0;
	while(~scanf("%d",&u)&&u)
	{
		for(int i=0;i<maxn;i++)iscut[i]=0,G[i].clear(),pre[i]=0;
		cnt = 0;
		
		scanf("%d",&v);
		G[u].pb(v),G[v].pb(u);
		while(~scanf("%d",&u)&&u)
		{
			scanf("%d",&v);
			G[u].pb(v),G[v].pb(u);
		}
		if(kase++)puts("");
		printf("Network #%d\n",kase);
		dfs(1,-1);
		int flag=1;
        for(int i=1;i<maxn;i++)
        {
            if(iscut[i])
            {
                printf("  SPF node %d leaves %d subnets\n",i,iscut[i]);
                flag=0;
            }
        }
        if(flag)printf("  No SPF nodes\n");
	}
	return 0;
}

题目链接

题目描述:求桥

跟求割点非常类似,求桥只需满足:low【v】>   pre【u】。这个意思是,u的子节点v最多只能连回v自己。

#include <bits/stdc++.h>
#define pb push_back
#define mk make_pair
#define pi pair<int,int>
using namespace std;
const int maxn = 200;

int pre[maxn],cnt=0;
vector<int>G[maxn];
vector<pi>ans;
int dfs(int u,int fa)
{
	int lowu = pre[u] = ++cnt;
	for(int i=0;i<G[u].size();i++)
	{
		int v = G[u][i];
		if(!pre[v])   //通过树边更新lowu 
		{
			int lowv = dfs(v,u);
			lowu = min(lowv,lowu);
			if(lowv > pre[u]) {
				ans.pb(mk(min(u,v),max(u,v)));
			}
		}
		else if(pre[v] < pre[u] && v != fa)  //通过反向边更新lowu 
		lowu = min(lowu,pre[v]);
	}
	return lowu;
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	while(m--)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		G[u].pb(v),G[v].pb(u);
	}
	dfs(1,-1);
	sort(ans.begin(),ans.end());
	for(int i=0;i<ans.size();i++) {
		cout<<ans[i].first<<' '<<ans[i].second<<'\n';
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值