【图论】【DFS】三校联考10.20T2

题意

寻找有多少条边满足:图中所有奇环都包含这条边,且这条边不属于任何偶环


分析:

最后一个性质好坑。。。一直在想那个性质结果T3都没来得及做…

直接建一个DFS树。因为是无向图,所以只存在树边和返祖边。然后很显然只有一条返祖边与树边形成的环是有效的。

并且!返祖边有贡献当且仅当全图只有一个奇环!!!。。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
void Read(int &x){
	x=0;
	char c;
	while(c=getchar(),c!=EOF&&(c<'0'||c>'9'));
	x=c-'0';
	while(c=getchar(),c!=EOF&&c>='0'&&c<='9')
		x=x*10+c-'0';	
}
struct node{
	int id,k;
	int x;
	bool operator <(const node &a)const {
		if(k!=a.k)
			return k<a.k;
		return id>a.id;
	}
	node () {}
	node (int k1,int id1,int x1):k(k1),id(id1),x(x1) {}
};
vector<node> a[MAXN];
int n,m,u,v;
int dep[MAXN],cnt1[MAXN],cnt2[MAXN];
set<int> used;
int sum;
void dfs(int x,int fa=0){
	cnt1[x]=cnt2[x]=0;
	for(int i=0;i<int(a[x].size());i++){
		int id=a[x][i].id;
		if(id==fa)
			continue;
		int u=a[x][i].x;
		if(dep[u]==0&&u!=1){
			dep[u]=dep[x]+1;
			dfs(u,id);	
		}
		else if(dep[u]>dep[x]){
			if((dep[u]-dep[x])%2==0){
				cnt1[u]++;
				cnt1[x]--;
				sum++;
			}
			else {
				cnt2[u]++;
				cnt2[x]--;	
			}
		}
	}
}
void solve(int x,int fa=0){
	for(int i=0;i<int(a[x].size());i++){
		int id=a[x][i].id;
		if(id==fa)
			continue;
		int u=a[x][i].x;
		if(dep[u]==0&&u!=1){
			dep[u]=dep[x]+1;
			a[x][i].k=1;
			solve(u,id);
			cnt1[x]=cnt1[x]+cnt1[u];
			cnt2[x]=cnt2[x]+cnt2[u];
		}
	}
	if(cnt2[x]==0&&cnt1[x]==sum&&fa!=0)
		used.insert(fa);
}
map<pair<int,int> ,int>mp;
set<int> spe;
int main(){
	freopen("voltage.in","r",stdin);
	freopen("voltage.out","w",stdout);
	SF("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		Read(u);
		Read(v);
		if(u>v)
			swap(u,v);
		if(mp.count(make_pair(u,v))){
			spe.insert(mp[make_pair(u,v)]);
			continue;
		}
		mp[make_pair(u,v)]=i;
		a[u].push_back(node(0,i,v));
		a[v].push_back(node(0,i,u));
	}
	memset(dep,0,sizeof dep);
	sum=0;
	dfs(1);
	memset(dep,0,sizeof dep);
	solve(1);	
	for(set<int>::iterator it=spe.begin();it!=spe.end();it++)
		if(used.count(*it))
			used.erase(*it);
	PF("%d",used.size()+(sum==1));
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值