2023ACM暑假训练day 1 最小生成树

DAY 1 最小生成树

训练地址:传送门

训练简介

2023-06-26
早上:ABCDJKLM
下午:EFH
晚上:G
发现早上都是kruskal,下午都是prim
这次训练板子题为主
后补 I 题 最小生成树的唯一性

7.12小整理,有时间再做一遍+整理[ ]

A 题

百炼oj 1251:Jungle Roads
题意:

思路:
...老长的英文题面,阿巴阿巴,慢慢看就知道,就是一道最小生成树板子题
村庄数不多,kruskal算法即可

//>>>Qiansui
#include<map>
#include<set>
#include<list>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
// typedef std::pair<int,int> pii;
// typedef std::pair<ll,ll> pll;
// typedef std::pair<ull,ull> pull;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
	return x*f;
}

using namespace std;

const int maxm=200+5,inf=0x3f3f3f3f,mod=998244353;
int n,k,fa[maxm],ans;

void pre(int x){
	ans=0;
	for(int i=0;i<=x;++i){
		fa[i]=i;
	}
	return ;
}

int findfa(int x){
	if(fa[x]==x) return x;
	else return fa[x]=findfa(fa[x]);
}

struct node{
	int u,v,w;
	bool operator <(const node& a)const{
		return a.w<w;
	}
};

void solve(){
	while(cin>>n){
		if(n==0) break;
		pre(n+130);
		char ch,ver;
		int cs,w,v,u;
		node t;
		priority_queue<node> q;
		for(int i=0;i<n-1;++i){
			cin>>ch>>cs;
			while(cs--){
				cin>>ver>>w;
				t.u=ch;
				t.v=ver;
				t.w=w;
				q.push(t);
			}
		}
		while(!q.empty()){
			t=q.top();
			q.pop();
			u=findfa(t.u);
			v=findfa(t.v);
			if(u!=v){
				ans+=t.w;
				fa[u]=v;
			}
		}
		cout<<ans<<'\n';
	}
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
//	cin>>_;
	while(_--){
		solve();
	}
	return 0;
}

B 题

最小生成树简单题

C 题

代码写错了

int u=findfa(i),v=findfa(j);
fa[u]=v;//wa原因:这里之前的提交写错了!!!

D 题

哪来的多输入啊。。。

J 题

。。。题目古怪的输出,固然是不用的。。。
不知道怎么评价

Huge input, scanf is recommended.
这句话只是给你看的,不需要输出。。。

L 题

偷了个dsu的板子

struct dsu{
	int n;
	vector<int> fa;
	dsu(int x):n(x),fa(n+1){
		for(int i=0;i<=x;++i) fa[i]=i;
	}
	int findfa(int x){
		return fa[x]==x?x:fa[x]=findfa(fa[x]);
	}
	void merge(int u,int v){
		int x=findfa(u),y=findfa(v);
		fa[x]=y;
		return ;
	}
};

M 题

与D题同题不同源,一个是poj,一个是hdu

E 题

题意有点没读懂。。。
百度看一下题意吧
暴露问题:prim算法的具体实现还需要再练习一下

参考资料:
https://www.cnblogs.com/J-william/p/6371718.html

F 题

依旧是prim算法的运用,后面找个时间,利用优先队列来写prim算法
prim模板题

H 题

及其水的一题

abc307个人训练

C题大模拟。。。不知道错在什么地方了,没有再仔细看
我觉得可能自己题目都看错了。。。
有时间再回顾一下

E题圆环染色问题,有个结论,见自己的博客
也可以用DP?可以看看

G 题

最小生成树简单题
还需输出建造的边,可以看看

I 题 判断最小生成树是否唯一

题意:
判断最小生成树是否唯一
思路:
考虑最小生成树的唯一性。如果一条边 不在最小生成树的边集中,并且可以替换与其 权值相同、并且在最小生成树边集 的另一条边。那么,这个最小生成树就是不唯一的。

对于 Kruskal 算法,只要计算为当前权值的边可以放几条,实际放了几条,如果这两个值不一样,那么就说明这几条边与之前的边产生了一个环(这个环中至少有两条当前权值的边,否则根据并查集,这条边是不能放的),即最小生成树不唯一。

下为代码:

//>>>Qiansui
#include<map>
#include<set>
#include<list>
#include<stack>
#include<cmath>
#include<queue>
#include<deque>
#include<cstdio>
#include<string>
#include<vector>
#include<utility>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<functional>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x,y,sizeof(x))
//#define int long long
// typedef std::pair<int,int> pii;
// typedef std::pair<ll,ll> pll;
// typedef std::pair<ull,ull> pull;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
	return x*f;
}

using namespace std;

const int maxm=1e4+5,inf=0x3f3f3f3f,mod=998244353;
int n,m,sum;
struct edge{
	int u,v,w;
}p[maxm];

struct dsu{
	int num;
	vector<int> fa;
	dsu(int x=maxm):num(x),fa(x+1){
		for(int i=0;i<=x;++i) fa[i]=i;
	}
	int findfa(int x){ return fa[x]==x?x:findfa(fa[x]); }
	void merge(int u,int v){
		fa[findfa(u)]=findfa(v);
		return ;
	}
};

bool kruskal(){
	bool f=false;
	sort(p,p+m,[](edge x,edge y){
		return x.w<y.w;
	});
	dsu ds(n);
	for(int i=0;i<m;++i){
		queue<edge> q;
		int len=p[i].w;
		while(i<m && len==p[i].w){
			if(ds.findfa(p[i].u)!=ds.findfa(p[i].v))
				q.push(p[i]);
			++i;
		}
		--i;
		while(!q.empty()){
			edge t=q.front();
			q.pop();
			if(ds.findfa(t.u)!=ds.findfa(t.v)){
				sum+=t.w;
				ds.merge(t.u,t.v);
			}else{
				return true;
			}
		}
	}
	return f;
}

void solve(){
	cin>>n>>m;
	for(int i=0;i<m;++i){
		cin>>p[i].u>>p[i].v>>p[i].w;
	}
	sum=0;
	if(kruskal()) cout<<"Not Unique!\n";
	else cout<<sum<<'\n';
	return ;
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _=1;
	cin>>_;
	while(_--){
		solve();
	}
	return 0;
}

posted @ 2023-07-09 12:00  Qiansui  阅读(39)  评论(0)    收藏  举报