最小生成树

最小生成树的各种算法

子图:从原图中选中一些顶点和边组成的图.

生成子图:选中一些边和所有顶点组成的图.

生成树:正好是一棵树的生成子图.

最小生成树:权值之和最小的生成树.
Prim算法

复杂度:O(n^2) $$

$$




#include<iostream>
using namespace std;
const int INF = 1e4;
const int N = 100;
bool s[N];
int closest[N]; //存储U集合中离U-V集合中最近的点
int lowcost[N]; //最近点间的距离
void Prim(int n,int u0,int c[N][N])
{
	s[u0]=true; //初始值在U集合中
	int i,j;
	for(i=1;i<=n;i++) //初始化lowcost和closest数组
	{
		if(i!=u0)
		{
			lowcost[i]=c[u0][i];
			closest[i]=u0;
			s[i]=false;
		}
		else
			lowcost[i]=0;
	}
	for(i=1;i<=n;i++)
	{
		int temp = INF;
		int t=u0;
		for(j=1;j<=n;j++) //在集合U-V中找到离集合U中最近的点
		{
			if(!s[j]&&(lowcost[j]<temp))
			{
				t=j;
				temp=lowcost[j];
			}
		}
		if(t==u0)
			break;
		s[t]=true;
		for(j=1;j<=n;j++) //更新closest和lowcost数组
		{
			if(!s[j]&&(c[t][j]<lowcost[j]))
			{
				lowcost[j]=c[t][j];
				closest[j]=t;
			}
		}
	}
}
int main()
{
	int n,c[N][N],m,u,v,w;
	int u0;
	cout<<"请输入节点数n和边数m:"<<endl;
	cin>>n>>m;
	int sumcost=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			c[i][j]=INF;
	cout<<"输入节点数u,v和边值w:"<<endl;
	for(int i=1;i<=m;i++)
	{
		cin>>u>>v>>w;
		c[u][v]=c[v][u]=w;
	}
	cout<<"输入任一节点u0:"<<endl;
	cin>>u0;
	Prim(n,u0,c);
	cout<<"数组lowcost的内容为:"<<endl;
	for(int i=1;i<=n;i++)
	{
		cout<<lowcost[i]<<" ";
		sumcost+=lowcost[i];
	}
	cout<<endl;
	cout<<"最小的花费是:"<<sumcost<<endl;
}

Kruskal算法

复杂度:O(e*logn)

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100;
int nodeset[N];
int n,m;
struct Edge{
	int u;
	int v;
	int w;
}e[N*N]; //边集
bool cmp(Edge x,Edge y)
{
	return x.w<y.w;
}
void Init(int n) //初始化点集,每个点为一个集合
{
	for(int i =1;i<=n;i++)
		nodeset[i]=i;
}
int Merge(int a,int b) //避圈法,若线的两端在同一点集里,则会产生回路,应避免
{
	int p=nodeset[a];
	int q=nodeset[b];
	if(p==q)
		return 0;
	for(int i=1;i<=n;i++) //将所有连接在一起的点构成同一点集
	{
		if(nodeset[i]==q)
			nodeset[i]=p;
	}
	return 1;
}
int Kurskal(int n)
{
	int ans=0;
	for(int i=0;i<m;i++)
		if(Merge(e[i].u,e[i].v))
		{
			ans+=e[i].w;
			n--;
			if(n==1)
				return ans;
		}
	return 0;
}
int main()
{
	cout<<"输入节点数n和边数m:"<<endl;
	cin>>n>>m;
	Init(n);
	cout<<"输入节点数u,v和边值w:"<<endl;
	for(int i=1;i<=m;i++)
		cin>>e[i].u>>e[i].v>>e[i].w;
	sort(e,e+m,cmp);
	int ans=Kurskal(n);
	cout<<"最小花费是:"<<ans<<endl;
	return 0;
}

并查集改进的Kruskal算法

复杂度:O(n^2) $$

$$

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100;
int father[N];
int n,m;
struct Edge{
	int u;
	int v;
	int w;
}e[N*N];
bool cmp(Edge x,Edge y)
{
	return x.w<y.w;
}
void Init(int n)
{
	for(int i =1;i<=n;i++)
		father[i]=i;
}
int Find(int x)
{
	if(x!=father[x])
		father[x]=Find(father[x]);
	return father[x];
}
int Merge(int a,int b)
{
	int p = Find(a);
	int q = Find(b);
	if(p==q)
		return 0;
	if(p>q)
		father[p]=q;
	else
		father[q]=p;
	return 1;
}
int Kurskal(int n)
{
	int ans=0;
	for(int i=0;i<m;i++)
		if(Merge(e[i].u,e[i].v))
		{
			ans+=e[i].w;
			n--;
			if(n==1)
				return ans;
		}
	return 0;
}
int main()
{
	cout<<"输入节点数n和边数m:"<<endl;
	cin>>n>>m;
	Init(n);
	cout<<"输入节点数u,v和边值w:"<<endl;
	for(int i=1;i<=m;i++)
		cin>>e[i].u>>e[i].v>>e[i].w;
	sort(e,e+m,cmp);
	int ans=Kurskal(n);
	cout<<"最小花费是:"<<ans<<endl;
	return 0;
}

分治法

二分搜索

循环搜索

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int M=100;
int x,n,i;
int s[M];
int BinarySearch(int n,int s[],int x)
{
	int low=0,high=n-1,middle;
	while(low<=high)
	{
		middle=(low+high)/2;
		if(x==s[middle])
			return middle;
		else if(x<s[middle])
			high=middle-1;
		else
			low=middle+1;
	}
	return -1;
}
int main()
{
	cout<<"输入数列元素个数n:"<<endl;
	while(cin>>n)
	{
		cout<<"依次输入数列元素:"<<endl;
		for(i=0;i<n;i++)
			cin>>s[i];
		sort(s,s+n);
		cout<<"排序后的数组:"<<endl;
		for(i=0;i<n;i++)
			cout<<s[i]<<" ";
		cout<<endl;
		cout<<"输入要查找的元素:"<<endl;
		cin>>x;
		i=BinarySearch(n,s,x);
		if(i==-1)
			cout<<"没有查找到"<<endl;
		else
			cout<<"查找的元素在第"<<i+1<<"位"<<endl;
	}
	return 0;
}

递归搜索

int recursionBS(int s[],int x,int low,int high)
{
	if(low>high)
		return -1;
	int middle=(low+high)/2;
	if(x==s[middle])
		return middle;
	else if(s<s[middle])
		return recursionBS(s,x,low,middle-1);
	else
		return recursionBS(s,x,middle+1,high);
}

合并排序

#include<iostream>
#include<cstdio>
#include<cstdlib>
//#include<algorithm>
using namespace std;
void Merge(int A[],int low,int mid,int high)
{
	int *B=new int[high-low+1];
	int i=low,j=mid+1,k=0;
	while(i<=mid&&j<=high)
	{
		if(A[i]<=A[j])
			B[k++]=A[i++];
		else
			B[k++]=A[j++];
	}
	while(i<=mid)
		B[k++]=A[i++];
	while(j<=high)
		B[k++]=A[j++];
	for(i=low,k=0;i<=high;i++)
		A[i]=B[k++];
}
void MergeSort(int A[],int low,int high)
{
	if(low<high)
	{
		int mid=(low+high)/2;
		MergeSort(A,low,mid);
		MergeSort(A,mid+1,high);
		Merge(A,low,mid,high);
	}
}
int main()
{
	int n,A[100];
	cout<<"输入元素个数:"<<endl;
	cin>>n;
	cout<<"输入每个元素:"<<endl;
	for(int i=0;i<n;i++)
		cin>>A[i];
	MergeSort(A,0,n-1);
	cout<<"合并排序结果为:"<<endl;
	for(int i=0;i<n;i++)
		cout<<A[i]<<" ";
	cout<<endl;
	return 0;
}

快速排序

原始

#include<iostream>
using namespace std;
int Partition(int r[],int low,int high)
{
	int i=low,j=high,pivot=r[low];
	while(i<j)
	{
		while(i<j&&r[j]>pivot) j--;
		if(i<j)
			swap(r[i++],r[j]);
		while(i<j&&r[i]<=pivot) i++;
		if(i<j)
			swap(r[i],r[j--]);
	}
	return i;
}
void QuickSort(int r[],int low,int high)
{
	int mid;
	if(low<high)
	{
		mid=Partition(r,low,high);
		QuickSort(r,low,mid-1);
		QuickSort(r,mid+1,high);
	}
}
int main()
{
	int n,A[100];
	cout<<"输入元素个数:"<<endl;
	cin>>n;
	cout<<"输入每个元素:"<<endl;
	for(int i=0;i<n;i++)
		cin>>A[i];
	QuickSort(A,0,n-1);
	cout<<"快速排序结果为:"<<endl;
	for(int i=0;i<n;i++)
		cout<<A[i]<<" ";
	cout<<endl;
	return 0;
}

改进

可减少交换次数,提高效率

int Partition2(int r[],int low,int high)
{
	int i=low,j=high,pivot=r[low];
	while(i<j)
	{
		while(i<j&&r[j]>pivot)
			j--;
		while(i<j&&r[i]<=pivot)
			i++;
		if(i<j)
			swap(r[i++],r[j--]);
	}
	if(r[i]>pivot)
	{
		swap(r[i-1],r[low]);
		return i-1;
	}
	swap(r[i],r[low]);
	return i;
}

大整数乘法

#include<iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
#define M 100
char sa[100],sb[100];
typedef struct _Node
{
	int s[M];
	int l;
	int c;
}Node,*pNode;
void cp(pNode src,pNode des,int st,int l) //拆分函数,st为起点
{
	int i,j;
	for(i=st,j=0;i<st+l;i++,j++)
		des->s[j]=src->s[i];
	des->l=l;
	des->c=st+src->c;
}
void add(pNode pa,pNode pb,pNode ans)
{
	int i,cc,k,palen,pblen,len;
	int ta,tb;
	pNode temp;
	if((pa->c)<(pb->c)) //保证幂指数较大的为pa
	{
		temp=pa;
		pa=pb;
		pb=temp;
	}
	ans->c=pb->c; //结果的幂指数等于较小的幂指数
	cc=0; //进位初始为0
	palen=pa->l+pa->c; 
	pblen=pb->l+pb->c;
	if(palen<pblen)
		len=pblen; 
	else
		len=palen; //总的长度为最长的那一个
	k=pa->c-pb->c; //pa需要补充的0的个数
	for(i=0;i<len-ans->c;i++)
	{
		if(i<k) //pa的前k位都是补充的0
			ta=0;
		else
			ta=pa->s[i-k];
		if(i< pb->l)
			tb=pb->s[i];
		else //超过pb长度的位pb的值都是0
			tb=0;
		if(i>=pa->l+k) //超过pa长度的位pa的值都是0
			ta=0;
		ans->s[i]=(ta+tb+cc)%10;
		cc=(ta+tb+cc)/10;
	}
	if(cc)
		ans->s[i++]=cc;
	ans->l=i;
}
void mul(pNode pa,pNode pb,pNode ans)
{
	int i,cc,w;
	int ma=pa->l>>1,mb=pb->l>>1;
	Node ah,al,bh,bl;
	Node t1,t2,t3,t4,z;
	pNode temp;
	if(!ma||!mb) //当pa或pb有一个只有1位时开始乘法
	{
		if(!ma) //保证pa为较大值
		{
			temp=pa;
			pa=pb;
			pb=temp;
		}
		ans->c=pa->c+pb->c; //结果的幂指数=两个乘数的幂指数之和
		w=pb->s[0]; //pb只有1位,用常数表示
		cc=0;
		for(i=0;i<pa->l;i++)
		{
			ans->s[i]=(w*pa->s[i]+cc)%10;
			cc=(w*pa->s[i]+cc)/10;
		}
		if(cc)
			ans->s[i++]=cc; //最后的进位填进数组最后
		ans->l=i;
		return;
	}
	cp(pa,&ah,ma,pa->l-ma);
	cp(pa,&al,0,ma);
	cp(pb,&bh,mb,pb->l-mb);
	cp(pb,&bl,0,mb);
	
	mul(&ah,&bh,&t1);
	mul(&ah,&bl,&t2);
	mul(&al,&bh,&t3);
	mul(&al,&bl,&t4);
	
	add(&t3,&t4,ans);
	add(&t2,ans,&z);
	add(&t1,&z,ans);
}
int main()
{
	Node ans,a,b;
	cout<<"输入大数1:"<<endl;
	cin>>sa;
	cout<<"输入大数2:"<<endl;
	cin>>sb;
	a.l=strlen(sa);
	b.l=strlen(sb);
	int z=0,i;
	for(i=a.l-1;i>=0;i--) //把输入的字符转为数字并倒序存入数组
		a.s[z++]=sa[i]-'0';  
	a.c=0;
	z=0;
	for(i=b.l-1;i>=0;i--)
		b.s[z++]=sb[i]-'0';
	b.c=0;
	mul(&a,&b,&ans);
	cout<<"结果为:"<<endl;
	for(i=ans.l-1;i>=0;i--)
		cout<<ans.s[i];
	cout<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值