Day3 生成树专题

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/87101970

A. UVALive 6437 Power Plant

题目

UVALive 6437

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=205;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1,ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
struct rec
{
	int x,y,z;
}edge[maxn*maxn];
int fa[maxn];
inline int get(int x)
{
	if (fa[x]==x) return x;
	return fa[x]=get(fa[x]);
}
inline bool cmp(rec a,rec b)
{
	return a.z<b.z;
}
int main()
{
	int t;read(t);
	for (int cnt=1;cnt<=t;++cnt)
	{
		int n,m,k,f,ans=0;
		read(n);read(m);read(k);
		for (int i=1;i<=n;++i)
			fa[i]=i;
		read(f);
		for (int i=2;i<=k;++i)
		{
			int x;read(x);
			fa[x]=f;
		}
		for (int i=1;i<=m;++i)
		{
			read(edge[i].x);
			read(edge[i].y);
			read(edge[i].z);
		}
		sort(edge+1,edge+m+1,cmp);
		for (int i=1;i<=m;++i)
		{
			int x=edge[i].x;
			int y=edge[i].y;
			if (get(x)==get(y)) continue;
			fa[fa[x]]=fa[y];
			ans+=edge[i].z;
		}
		printf("Case #%d: %d\n",cnt,ans);
	}
	return 0;
}

B. UVA 10369 Arctic Network

题目

LUOGU UVA10369

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1,ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
struct rec
{
	int fr,to;
	double z;
}edge[maxn*maxn];
int fa[maxn],dx[maxn],dy[maxn];
inline int get(int x)
{
	return fa[x]==x?x:fa[x]=get(fa[x]);
}
inline void combine(int x,int y)
{
	int xx=get(x),yy=get(y);
	if (xx!=yy) fa[xx]=yy;
}
inline bool cmp(rec a,rec b)
{
	return a.z<b.z;
}
int main()
{
	int t;read(t);
	while (t--)
	{
		int m,n,len=0,tot=0;
		double ans=0.00;
		read(m);read(n);
		for (int i=1;i<=n;++i)
		{
			fa[i]=i;
			read(dx[i]);read(dy[i]);
		}
		for (int i=1;i<n;++i)
			for (int j=i+1;j<=n;++j)
				edge[++len].fr=i,edge[len].to=j,
				edge[len].z=sqrt(double((dx[i]-dx[j])*(dx[i]-dx[j]))+double((dy[i]-dy[j])*(dy[i]-dy[j])));
		sort(edge+1,edge+len+1,cmp);
		for (int i=1;i<=len;++i)
		{
			if (get(fa[edge[i].fr])!=get(fa[edge[i].to]))
			{
				combine(edge[i].fr,edge[i].to);
				++tot;
				ans=edge[i].z;
			}
			if (tot==n-m) break;
		}
		printf("%.2lf\n",ans);
	}
	return 0;
}

C. BZOJ 1232: [Usaco2008Nov]安慰奶牛cheer

题目

BZOJ 1232

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1,ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
struct rec
{
	int x,y,z;
}edge[maxn<<1];
int fa[maxn],c[maxn],ans=0x3f3f3f3f,tot;
inline int get(int x)
{
	if (x==fa[x]) return x;
	return fa[x]=get(fa[x]);
}
inline bool cmp(rec a,rec b)
{
	return a.z<b.z;
}
int main()
{
	int n,p;
	read(n);read(p);
	for (int i=1;i<=n;++i)
	{
		read(c[i]);
		ans=min(ans,c[i]);
		fa[i]=i;
	}
	for (int i=1;i<=p;++i)
	{
		int x,y,z;
		read(x);read(y);read(z);
		z=(z<<1)+c[x]+c[y];
		edge[i].x=x,edge[i].y=y,edge[i].z=z;
	}
	sort(edge+1,edge+p+1,cmp);
	for (int i=1;i<=p;++i)
	{
		int x=get(edge[i].x);
		int y=get(edge[i].y);
		if (x!=y)
		{
			fa[x]=y;
			++tot;
			ans+=edge[i].z;
		}
		if (tot==n-1) break;
	}
	printf("%d\n",ans);
	return 0;
}

D. UVA1151 Buy or Build

题目

UVA1151 Buy or Build
POJ 2784

代码

#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=1e3+5;
const int maxm=5e5+5e2;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1,ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
struct Node
{
	int x,y;
}node[maxn];
struct rec
{
	int x,y,z;
	bool operator < (const rec &a) const
	{
		return z<a.z;
	}
}edge[maxm];
int fa[maxn],cost[10];
int n,q,num;
vector<int>g[10];
inline int get(int x)
{
	if (fa[x]==x) return x;
	return fa[x]=get(fa[x]);
}
inline int combine(int x,int y)
{
	int xx=get(x),yy=get(y);
	if (xx==yy) return false;
	fa[xx]=yy;
	return true;
}
int Kruskal()
{
    int ans=0,cnt=0;
    for (int i=0;i<num;++i)
    {
        if (combine(edge[i].x,edge[i].y))
        {
            ans+=edge[i].z;
            ++cnt;
        }
        if (cnt==n-1) break;
    }
    return ans;
}
int main()
{
//	int t;read(t);
//	while (t--)
//	{
		read(n);read(q);
		for (int i=0;i<q;++i)
		{
			g[i].clear();int number;
			read(number);read(cost[i]);
			for (int j=0;j<number;++j)
			{
				int x;read(x);
				g[i].push_back(x);
			}
		}
		for (int i=1;i<=n;++i)
		{
			read(node[i].x);
			read(node[i].y);
		}
		for (int i=1;i<=n;++i)
			for (int j=i+1;j<=n;++j)
				edge[num].x=i,edge[num].y=j,
				edge[num++].z=(node[i].x-node[j].x)*(node[i].x-node[j].x)+(node[i].y-node[j].y)*(node[i].y-node[j].y);
		sort(edge,edge+num);
		for (int i=0;i<=n;++i)
			fa[i]=i;
    	int ans=Kruskal();
    	for (int i=0;i<(1<<q);++i)
    	{
			for (int k=0;k<=n;++k)
				fa[k]=k;
			int all=0;
			for (int j=0;j<q;++j)
			{
				if (!((i>>j)&1)) continue;//if (1!=(i>>j))
				all+=cost[j];
				for (int k=1;k<g[j].size();++k)
					combine(g[j][k],g[j][0]);
			}
			ans=min(ans,all+Kruskal());
		}
		printf("%d\n",ans);
//		if (t) puts("");
//	}
	return 0;
}

E. POJ 3522 Slim Span

题目

POJ 3522

题意

给出一个图,若图连通,则求最大边与最小边差值最小的生成树,输出最小差值。否则输出-1。

题解

其实就是求边权差值最小的生成树。
1.首先我们看一下数据范围, 2 n 100 0 m n ( n 1 ) / 2 2 ≤ n ≤ 100 , 0 ≤ m ≤ n(n − 1)/2 ,很小,所以我们就可以直接枚举最小边。
2.接着跑最小生成树,就是瓶颈生成树,因为最小生成树有一个很重要的性质:在构造生成树时有可能选择不同的边,但最小生成树的权是唯一的!所以在用kruskal算法时第一次加入的必然是最小生成树的最小边权值,最小边确定后,==最小生成树的最大边的权值是所以生成树中最小的,==即为瓶颈生成树。
3.然后更新答案即可。

代码

#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=2e5+10;
char buf[1<<15],*fs,*ft;
inline char getc(){return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++;}
inline int read()
{
	int num=0,f=1;char ch=getchar();
	while (!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) num=(num<<3)+(num<<1)+(ch^48), ch=getchar();
	return num*f;
}
struct rec
{
	int x,y,z;
}edge[maxn];
int fa[maxn],ans;
inline bool operator < (rec a,rec b)
{
	return a.z<b.z;
}
inline int get(int x)
{
	if (x==fa[x]) return x;
	return fa[x]=get(fa[x]);
}
int main()
{
	while (1)
	{
		int n=read(),m=read(),i=0;
		if (!n && !m) break;
		if	(n==1)
		{
			puts("0");
			exit(0);
		}
		for (i=1;i<=m;++i)
			edge[i].x=read(),edge[i].y=read(),edge[i].z=read();
		sort(edge+1,edge+m+1);
		ans=edge[m].z;//差值初始化
		for (int k=1;k<=m;++k)//以k为最小边进行枚举
		{
			int sum=0;//最小生成树的边数
			for (i=1;i<=n;++i)//生成树初始化
				fa[i]=i;
			for (i=k;i<=m;++i)//求最小生成树
			{
				int x=get(edge[i].x);
				int y=get(edge[i].y);
				if (x==y) continue;
				fa[x]=y;
				++sum;
				if (sum==n-1)//已构成一个最小生成树(从定义出发)
				{
					ans=min(ans,edge[i].z-edge[k].z);//最大边减去最小边
					break;
				}
			}
			if (i==m+1)	break;
		}
		if (ans==edge[m].z)//ans未经过改变,说明此图未连通
			puts("-1");
		else
			printf("%d\n",ans);
	}
	return 0;
}

F. UVA10816 Travel in Desert

题目

UVA10816

题解

首先,这是一道 生成树最短路 的题。

代码

#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=1e4+5;
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}
struct MST
{
	int fr,to;
	double tem,len;
	friend bool operator < (const MST &a,const MST &b)
	{
        return a.tem<b.tem;
    }
}tree[maxn<<1];
int ver[maxn<<1],Next[maxn<<1],head[maxn],len,num;
double edge[maxn<<1];
inline void add(int x,int y,double z)
{
	ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
inline void insert(int x,int y,double tem,double dis)
{
	tree[++num].fr=x,tree[num].to=y,tree[num].len=dis,tree[num].tem=tem;
}
int fa[maxn],n,m,s,t;
inline int get(int x)
{
	return fa[x]==x?x:fa[x]=get(fa[x]);
}
struct HeapNode
{
    int u;//点
    double d;//距离
    friend bool operator < (const HeapNode &a,const HeapNode &b)
	{
        return a.d>b.d;
    }
};
priority_queue<HeapNode> q;
vector<int> path;
double maxtem,dist[maxn];
bool vis[maxn];
inline void heap_dijkstra()
{
	for (register int i=1;i<=n;++i)
		dist[i]=0x3f3f3f3f,vis[i]=0,fa[i]=0;
	dist[s]=0;
	q.push((HeapNode){s,dist[s]});
	while (!q.empty())
	{
		int x=q.top().u;
		q.pop();
		if (vis[x]) continue;
		vis[x]=1;
		for (int i=head[x];i;i=Next[i])
		{
			int y=ver[i];
			double z=edge[i];
			if (dist[y]>dist[x]+z)
			{
				dist[y]=dist[x]+z;
				fa[y]=x;//再跑最短路的同时,用并查集确定x与y之间的关系,即x是y的父亲
				q.push((HeapNode){y,dist[y]});
			}
		}
	}
	register int x=t;
    path.clear();
    while (x!=s)//从终点出发,一直在树上遍历到起点,就刚好把路径加入到path[]中
	{
        path.push_back(x);
        x=fa[x];
    }
    path.push_back(s);
    for (register int i=path.size()-1;i>=1;--i)
        printf("%d ",path[i]);
    printf("%d\n",path[0]);
}
int main()
{
	while (~scanf("%d%d",&n,&m))
	{
		num=len=0;maxtem=0;
		memset(head,0,sizeof(head));
		memset(fa,0,sizeof(fa));
		read(s);read(t);
		register double te,w;
		for (register int i=1,fr,to;i<=m;++i)
		{
			read(fr);read(to);
			scanf("%lf%lf",&te,&w);
			insert(fr,to,te,w);
		}
		for (register int i=1;i<=n;++i)
			fa[i]=i;
		sort(tree+1,tree+m+1);
		for (register int i=1;i<=m;++i)
		{
			register int x=get(tree[i].fr),y=get(tree[i].to);
			if (x!=y)
			{
				fa[x]=y;
				maxtem=max(maxtem,tree[i].tem);
				if (get(s)==get(t)) break;
			}
		}
		for (int i=1;i<=m;++i)
		{
			if (tree[i].tem>maxtem) break;;
            add(tree[i].fr,tree[i].to,tree[i].len);
            add(tree[i].to,tree[i].fr,tree[i].len);
		}
		heap_dijkstra();
		printf("%.1f %.1f\n",dist[t],maxtem);
	}
	return 0;
}

G. POJ 1639 Picnic Planning

题目

POJ 1639

代码

暂时还没有了噻!!QWQ

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/87101970