最小生成树

来源:互联网 发布:拍照软件有哪些 编辑:程序博客网 时间:2024/05/21 21:35

       最小生成树有两种不同算法,一种克鲁斯卡尔算法,一种prime算法,两者各有好处,克鲁斯卡尔需要排序,prime算法每次取和节点相连的最小值,依次往后递增。比较起来克鲁斯卡尔复杂度比较高,两者在不同情况有不同的应用,克鲁斯卡尔比较适用于稀疏图,而prime算法比较适用于稠密图,而经过堆优化的prime算法也适用于稀疏图。

     克鲁斯卡尔算法思想:

     将所有的节点和权值信息加入结构体数组,每次标记一个已经用过的节点,(此处应用到并查集),每次将节点存入标记数组的对应节点下标中,下次遇到该节点,应用并查集搜索该节点的头结点和已经用过的节点是否有相同的头节点,找到路条数为节点个数减一截止。

     prime算法思路:将所有节点与二维数组的下标对应,i(1....n)每次寻找该节点所连接节点中权值最小的节点,以权值最小节点为中间节点,下一次从该节点往下找其他节点,每次循环都找权值最小的值。直到二维数组遍历完

      

There are N (2<=N<=600) cities,each has a value of happiness,we consider two cities A and B whose value of happiness are VA and VB,if VA is a prime number,or VB is a prime number or (VA+VB) is a prime number,then they can be connected.What's more,the cost to connecte two cities is Min(Min(VA , VB),|VA-VB|). 
Now we want to connecte all the cities together,and make the cost minimal.
Input
The first will contain a integer t,followed by t cases. 
Each case begin with a integer N,then N integer Vi(0<=Vi<=1000000).
Output
If the all cities can be connected together,output the minimal cost,otherwise output "-1";
Sample Input
251234544444
Sample Output
 4
 -1
解题思路:
由于题目中需要用到素数,并且数组范围比较大,因此求素数时间需要优化,此处本人运用筛法求素数,缩短时间复杂度,防止超时,而后运用prime算法,计算权值最小结果。模板水题。
代码:
#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h> int b[2000010]={0};int min(int a,int b){return a<b?a:b;}void fun()//筛法求素数{    int i;int j;    b[1]=1;b[0]=1;    for(i=2;i<2000000;i++)    {       if(b[i]==0)       for(j=2;j*i<=2000010;j++)        b[i*j]=1;}}int main(){int i,j,k,m,n,t,sum,inf,c1,x,y;int a[700];int c[700][700];int f[700];int f1[700];inf=9999999;fun();scanf("%d",&t);while(t--){scanf("%d",&m);memset(a,0,sizeof(a));memset(c,0,sizeof(c));memset(f1,0,sizeof(f1));memset(f,0,sizeof(f));    for(i=1;i<=m;i++)     scanf("%d",&a[i]);    for(i=1;i<=m;i++)      for(j=1;j<=m;j++)//数据处理,将节点之间的联系加入二维数组。      {        if(j<i)         continue;        else if(i==j)         { c[i][j]=inf; continue;}        if(b[a[i]]==0||b[a[j]]==0||b[a[i]+a[j]]==0)        {        int m0=min(min(a[i],a[j]),abs(a[i]-a[j]));        c[i][j]=m0;        c[j][i]=m0;}  else   { c[i][j]=inf; c[j][i]=inf; }  }    for(i=1;i<=m;i++)   f[i]=c[1][i];    //从1开始,将和节点1相连的权值存入以为数组。方便后面的遍历。  f1[1]=1;         //标记变量,防止连接图中形成回路。  c1=1;sum=0;y=1;  while(c1<m)  {    x=inf;    for(i=1;i<=m;i++)//寻找该节点所相连的权值最小的值。      {      if(f1[i]==0&&x>f[i])       {x=f[i];j=i;}  }   c1++;f1[j]=1;sum+=f[j];   if(j>m)    continue;   for(k=1;k<=m;k++)//以j为下一个节点,跟新一维数组的值。   {    if(f1[k]==0&&f[k]>c[j][k])       f[k]=c[j][k]; //此处是难点,不容易理解。下面有详解
                  }                 }               if(x!=inf)               printf("%d\n",sum);                else                printf("-1\n");         }           return 0;}

prime算法连接图的时间,相当于每次往数组中存入一个节点,每次寻找所有存入队列节点所连接

节点中权值最小的值。而这个过程可以用数组模拟出来,而此处,每次判断j节点到下一个节点和上

一个节点到该循环节点谁最小,将较小值留下来,以便实现 “每次寻找所有存入队列节点所连接节

点中权值最小的值”。可以由自己按照模拟一遍,更容易理解。


原创粉丝点击