刷題記錄 kuangbin帶你飛專題六:最小生成樹

全是憨批題的專題
可能是爲了在並查集之後給人恢復信心
簡略寫一下

1.POJ 1251 Jungle Roads

模板題,把字母轉化爲數字

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
int n,m,a[5005],ans,cnt,num;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v,w;
}e[200005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+num,cmp);
	for(int i=1;i<=num;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans+=e[i].w;
		hb(u,v);
		if(++cnt==n-1)break;
	}
}
int main(){
	while(cin>>n){
		for(int i=1;i<=n;i++){
			a[i]=i;
		}
		if(n==0)break;
		memset(e,0,sizeof(e));
		char u[5],v[5];
		int t,w;
		num=0,cnt=0;
		ans=0;
		for(int i=1;i<=n-1;i++){
			scanf("%s%d",u,&t);
			for(int j=1;j<=t;j++){
				scanf("%s%d",v,&w);
				e[++num].u=u[0]-'A'+1;
				e[num].v=v[0]-'A'+1;
				e[num].w=w;
			}
		}
		krus();
		cout<<ans<<endl;
	}
	return 0;
}

2.POJ 1287 Networking

模板題

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
int n,m,a[5005],ans,cnt,num;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v,w;
}e[200005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+m,cmp);
	for(int i=1;i<=m;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans+=e[i].w;
		hb(u,v);
		if(++cnt==n-1)break;
	}
}
int main(){
	while(cin>>n){
		for(int i=1;i<=n;i++){
			a[i]=i;
		}
		if(n==0)break;
		memset(e,0,sizeof(e));
		cin>>m;
		num=0,cnt=0;
		ans=0;
		for(int i=1;i<=m;i++){
			e[i].u=read();
			e[i].v=read();
			e[i].w=read();
		}
		krus();
		cout<<ans<<endl;
	}
	return 0;
}

3.POJ 2031 Building a Space Station

三維歐幾里得距離,如果距離小於r1+r2則爲0,否則減去

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
int n,m,a[5005];
double ans,cnt;
int num;
double juli(double x1,double y1,double z1,double x2,double y2,double z2){
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));
}
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct node{
	double x,y,z,r;
}pos[1005];
struct edge{
	int u,v;
	double w;
}e[200005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+num,cmp);
	for(int i=1;i<=num;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans+=e[i].w;
		hb(u,v);
		if(++cnt==n-1)break;
	}
}
int main(){
	while(cin>>n){
		for(int i=1;i<=n;i++){
			a[i]=i;
		}
		if(n==0)break;
		memset(e,0,sizeof(e));
		num=0,cnt=0;
		ans=0;
		for(int i=1;i<=n;i++){
			scanf("%lf%lf%lf%lf",&pos[i].x,&pos[i].y,&pos[i].z,&pos[i].r);
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(i==j)continue;
				e[++num].u=i;
				e[num].v=j;
				double w=juli(pos[i].x,pos[i].y,pos[i].z,pos[j].x,pos[j].y,pos[j].z);
				if(w<=pos[i].r+pos[j].r)w=0;
				else w-=pos[i].r+pos[j].r;
				e[num].w=w;
			}
		}
		krus();
		printf("%.3f\n",ans);
	}
	return 0;
}

4.POJ 2421 Constructing Roads

給個距離矩陣,再給已有的邊,直接把已有的加入並查集或者距離設置爲0都可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
using namespace std;
int n,m,a[5005],ans,cnt,num;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v,w;
}e[200005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+num,cmp);
	for(int i=1;i<=num;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans+=e[i].w;
		hb(u,v);
		if(++cnt==n-1)break;
	}
}
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int w;
			w=read();
			if(j>i){
				e[++num].u=i;
				e[num].v=j;
				e[num].w=w;
			}
		}
	}
	m=read();
	for(int i=1;i<=m;i++){
		int x,y;
		x=read(),y=read();
		hb(x,y);
	}
	krus();
	cout<<ans;
	return 0;
}

5.ZOJ 1586 QS Network

邊權加上兩點點權

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
using namespace std;
int n,m,a[5005],ans,cnt,num,cost[5005];
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v,w;
}e[200005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+num,cmp);
	for(int i=1;i<=num;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans+=e[i].w;
		hb(u,v);
		if(++cnt==n-1)break;
	}
}
int main(){
	int t;
	t=read();
while(t--){
		n=read();
		num=0,ans=0,cnt=0;
		memset(e,0,sizeof(e));
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	for(int i=1;i<=n;i++){
		cost[i]=read();
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int w;
			w=read();
			if(j>i){
				e[++num].u=i;
				e[num].v=j;
				e[num].w=w+cost[i]+cost[j];
			}
		}
	}
	krus();
	cout<<ans<<endl;
	}
	return 0;
}

6.POJ 1789 Truck History

兩個字符串中不同字符的數量爲權,稠密圖,適合prim,特意學了一下堆優化prim
之前對vector用memset一直MLE後來換了clear才過,才知道不能對vector和string用memset,會發生內存泄漏,記住!

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
int  k,n,m,cnt,ans,sum;
int dis[2005],vis[2005];
struct edge{
	int v,w;
};
struct node{
	int w,now;
	bool operator <(const node&x)const
	{
		return w>x.w;
	}
};
vector<edge>g[2005];
priority_queue<node>q;
void prim(){
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[1]=0;
	q.push((node){0,1});
	while(!q.empty()&&cnt<n){
		node x=q.top();
		q.pop();
		int d=x.w;
		int u=x.now;
		if(vis[u])continue;
		cnt++;
		sum+=d;
		vis[u]=1;
		for(int i=0;i<g[u].size();i++){
			if(g[u][i].w<dis[g[u][i].v]){
				dis[g[u][i].v]=g[u][i].w;
				q.push((node){dis[g[u][i].v],g[u][i].v});
			}
		}
	}
	while(!q.empty())q.pop();
	return;
}
string a[2005];
int getd(int i,int j){
	int c=0;
	for(int x=0;x<7;x++){
		if(a[i][x]!=a[j][x])c++;
	}
	return c;
}
int main(){
	while(cin>>n){
		if(n==0)break;
		cnt=0,sum=0,ans=0;
//		memset(g,0,sizeof(g));
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		for(int i=1;i<=n;i++){
			for(int j=i+1;j<=n;j++)
			{
				int w=getd(i,j);
				g[i].push_back((edge){j,w});
				g[j].push_back((edge){i,w});
			}
		}
		prim();
		if(cnt==n)printf("The highest possible quality is 1/%d.\n",sum);
		for(int i=1;i<=n;i++){
			g[i].clear();
		}
	}
	return 0;
}

7.POJ 2349 Arctic Network

最小生成樹的最大邊

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
int n,m,a[5005],cnt,bs=1,qq;
int dis[1005][1005];
double ans;
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v;
	double w;
}e[1000005];
struct node{
	double x,y;
}pos[1000005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+bs,cmp);
	for(int i=1;i<=bs;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans=max(ans,e[i].w);
		hb(u,v);
		if(++cnt==n-m)break;
	}
}
int main(){
	int tt;
	cin>>tt;
	while(tt--){
	m=read(),n=read();
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	cnt=0,ans=0,bs=1;
	for(int i=1;i<=n;i++){
		pos[i].x=read();
		pos[i].y=read();
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			e[bs].u=i;
			e[bs].v=j;
			e[bs].w=(double)sqrt((pos[i].x-pos[j].x)*(pos[i].x-pos[j].x)+(pos[i].y-pos[j].y)*(pos[i].y-pos[j].y));
			bs++;
		}
	}
	krus();
	printf("%.2f\n",ans);
	}
	return 0;
}

8.POJ 1751 Highways

給一些權爲0的邊,求最小生成樹中非0邊的連接的端點

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
int n,m,a[5005],cnt,bs=1,qq;
int dis[1005][1005];
double ans;
double juli(double x1,double y1,double x2,double y2){
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v;
	double w;
}e[1000005];
struct node{
	double x,y;
}pos[1000005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+bs,cmp);
	for(int i=1;i<=bs;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		if(e[i].w!=0){
			printf("%d %d\n",u,v);
		}
		hb(u,v);
		if(++cnt==n-1)break;
	}
}
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	cnt=0,ans=0,bs=1;
	for(int i=1;i<=n;i++){
		pos[i].x=read();
		pos[i].y=read();
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			e[bs].u=i;
			e[bs].v=j;
			e[bs].w=juli(pos[i].x,pos[i].y,pos[j].x,pos[j].y);
			bs++;
		}
	}
	m=read();
	for(int i=1;i<=m;i++){
		e[bs].u=read();
		e[bs].v=read();
		e[bs].w=0;
		bs++;
	}
	krus();
	return 0;
}

9.POJ 1258 Agri-Net

跟前面某題一樣的模板題

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
using namespace std;
int n,m,a[5005],ans,cnt,num,cost[5005];
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
struct edge{
	int u,v,w;
}e[200005];
int find(int x){
	if(a[x]==x)return x;
	return a[x]=find(a[x]);
}
void hb(int y,int x){
	a[find(y)]=find(x);
	return;
}
bool cmp(edge a,edge b){
	return a.w<b.w;
}
void krus(){
	sort(e+1,e+1+num,cmp);
	for(int i=1;i<=num;i++){
		int u,v;
		u=e[i].u;
		v=e[i].v;
		if(find(u)==find(v))continue;
		ans+=e[i].w;
		hb(u,v);
		if(++cnt==n-1)break;
	}
}
int main(){
while(cin>>n){
	num=0,ans=0,cnt=0;
	memset(e,0,sizeof(e));
	for(int i=1;i<=n;i++){
		a[i]=i;
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int w;
			w=read();
			if(j>i){
				e[++num].u=i;
				e[num].v=j;
				e[num].w=w;
			}
		}
	}
	krus();
	cout<<ans<<endl;
	}
	return 0;
}

10.POJ 3026 Borg Maze

每個點都能作爲出發點,bfs每個點到其他點的距離建邊

11.POJ 1679 The Unique MST

次小生成樹模板題

#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf =0x3f3f3f3f;
int n,m;
struct node{
	int u,v,w;
	int vis;
}e[20010];
vector<int>g[110];
int f[105],maxx[105][105];
bool cmp(node a,node b){
	return a.w<b.w;
}
int find(int x){
	if(f[x]==x)return x;
	return f[x]=find(f[x]);
}
void krus(){
	sort(e+1,e+1+m,cmp);
	for(int i=0;i<=n;i++){
		g[i].clear();
		g[i].push_back(i);
		f[i]=i;
	}
	int sum=0,cnt=0;
	for(int i=1;i<=m;i++){
		if(cnt==n-1)break;
		int u=e[i].u;
		int v=e[i].v;
		if(find(u)==find(v))continue;
		u=find(u);
		v=find(v);
		e[i].vis=1;
		cnt++;
		sum+=e[i].w;
		for(int j=0;j<g[u].size();j++){
			for(int k=0;k<g[v].size();k++){
				maxx[g[u][j]][g[v][k]]=maxx[g[v][k]][g[u][j]]=e[i].w;
			}
		}
		f[find(u)]=find(v);
		for(int j=0;j<g[u].size();j++){
			g[v].push_back(g[u][j]);
		}
	}
	int ss=inf;
	for(int i=1;i<=m;i++){
		if(!e[i].vis){
			ss=min(ss,sum+e[i].w-maxx[e[i].u][e[i].v]);
		}
	}
	if(ss>sum){
        printf("%d\n",sum);
	}
	else printf("Not Unique!\n");
}
int main(){
	int t;
	cin>>t;
	while(t--){
		cin>>n>>m;
		for(int i=1;i<=m;i++){
			scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
            e[i].vis = 0;
		}
		krus();
	}
	return 0;
}

12.HDU 1233 還是暢通工程

純模板

13.HDU 1301 Jungle Roads

跟T1一樣

14.HDU 1875 暢通工程再續

跟之前給座標求距離的題一樣

這個專題很快速的搞完了
接着弄完生成樹專題,然後
六月
打算搞一整個月數論和DP,雖然以後我不負責這一塊,但是至少要會基礎內容,不然隊友卡了的時候我都不能提供思路

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章