刷题记录 kuangbin带你飞专题六:最小生成树

全是憨批题的专题
可能是为了在并查集之后给人恢复信心
简略写一下

1.POJ 1251 Jungle Roads

模板题,把字母转化为数字

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
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,虽然以后我不负责这一块,但是至少要会基础内容,不然队友卡了的时候我都不能提供思路

你可能感兴趣的:(图论,最小生成树,kuangbin)