最小生成树的各种算法
子图:从原图中选中一些顶点和边组成的图.
生成子图:选中一些边和所有顶点组成的图.
生成树:正好是一棵树的生成子图.
最小生成树:权值之和最小的生成树.
Prim算法
#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算法
#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算法
#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;
}