清北学堂NOIP刷题营D4T3

文章描述了一个编程竞赛中的问题,涉及到树的重构和DFS序。当遇到一个节点的度数为奇数时,需要从其父节点(或祖父节点)借用,以确保每个子树的度数为偶数。代码实现了这一逻辑,遍历并处理多棵树的情况,判断是否能找到解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4045:7.26 合作(cooperate)

感觉这题挺巧妙的 比赛时没写出来...老师讲的也没完全听懂(老师讲的真不咋地(但是确实nb)) 多亏dalao

赛时成绩弱(

题目就是上面那个


因为今天专题是树 题中有提示所以想到树... 还是室友nb

 可以使用dfs序,先把一个图重构成为一个带有返祖边的树大概从这个变成这个

(不带返祖边)                                                      (带返祖边)

 那么就可以从根节点开始,如果当前节点的度数是偶数那么pass否则从父亲(爷爷)节点借就行了注意:可能有多个互不相连的图

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int dfsc;//the dfs order count
int dfn[300005];//the dfs order of dots
int cnt[300005],ans[300005];
vector<pair<int,int> > G[300005];//first int means what it's connected to next one saves id 
void dfs(int x,int pre,int fid) {
	dfn[x]=++dfsc;//change to dfs order
	int len=G[x].size();
	for(int i=0; i<len; i++) {
		int y=G[x][i].first;//for all the paths connected to x
		if(G[x][i].second==fid) continue;
		if(!dfn[y]) { //haven't yet ordered
			dfs(y,x,G[x][i].second);
		} else if(dfn[y]<dfn[x]) { //if y is the father of x
			ans[G[x][i].second]=x;
			cnt[x]++;
		}
	}
	if(fid&&(cnt[x]%2==1)) { //
		ans[fid]=x;
		cnt[x]++;
	} else {
		ans[fid]=pre;
		cnt[pre]++;
	}
}
int main() {
	cin>>n>>m;
	int x,y;
	for(int i=1; i<=m; i++) {
		cin>>x>>y;
		if(x==y){
			ans[i]=x;
			cnt[x]++;
		}
		G[x].push_back(pair<int,int> (y,i));
		G[y].push_back(pair<int,int> (x,i));
	}//save
	for(int i=1; n>=i; i++) {
		if(!dfn[i]) { //in case there are multiple trees
			dfsc=0;
			dfs(i,0,0);
			if(cnt[i]%2==1) {
				cout<<"NO"<<endl;
				return 0;
			}
		}
	}
	cout<<"YES";
	for(int i=1; i<=m; i++) {
		cout<<endl<<ans[i];
	}
	return 0;
}

 免登录复制版

#include<bits/stdc++.h>
using namespace std;
int n,m;
int dfsc;//the dfs order count
int dfn[300005];//the dfs order of dots
int cnt[300005],ans[300005];
vector<pair<int,int> > G[300005];//first int means what it's connected to next one saves id 
void dfs(int x,int pre,int fid) {
    dfn[x]=++dfsc;//change to dfs order
    int len=G[x].size();
    for(int i=0; i<len; i++) {
        int y=G[x][i].first;//for all the paths connected to x
        if(G[x][i].second==fid) continue;
        if(!dfn[y]) { //haven't yet ordered
            dfs(y,x,G[x][i].second);
        } else if(dfn[y]<dfn[x]) { //if y is the father of x
            ans[G[x][i].second]=x;
            cnt[x]++;
        }
    }
    if(fid&&(cnt[x]%2==1)) { //
        ans[fid]=x;
        cnt[x]++;
    } else {
        ans[fid]=pre;
        cnt[pre]++;
    }
}
int main() {
    cin>>n>>m;
    int x,y;
    for(int i=1; i<=m; i++) {
        cin>>x>>y;
        if(x==y){
            ans[i]=x;
            cnt[x]++;
        }
        G[x].push_back(pair<int,int> (y,i));
        G[y].push_back(pair<int,int> (x,i));
    }//save
    for(int i=1; n>=i; i++) {
        if(!dfn[i]) { //in case there are multiple trees
            dfsc=0;
            dfs(i,0,0);
            if(cnt[i]%2==1) {
                cout<<"NO"<<endl;
                return 0;
            }
        }
    }
    cout<<"YES";
    for(int i=1; i<=m; i++) {
        cout<<endl<<ans[i];
    }
    return 0;
}

既然你没登陆,赞也不用给了 我也理解

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值