最小生成树次生成树最短路劲0-背包总结

Posted gz153016

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树次生成树最短路劲0-背包总结相关的知识,希望对你有一定的参考价值。

1、最短路径

每组数据第一行是两个整数N、M(N<=100,M<=10000),

N表示成都的大街上有几个路口,

标号为1的路口是商店所在地,标号为N的路口是赛场所在地,

M则表示在成都有几条路。

N=M=0表示输入结束。

接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。

输入保证至少存在1条商店到赛场的路线。

Output

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample Input

N(有几个路口)  M(有几条路)

nodenum      edgenum

 

2                 1

1 2 3

 

3 3

 

1 2 5

2 3 5

3 1 2

 

0 0

 

Sample Output

3

2

 

SPFA版本:

 

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<climits>

#include<queue>

#include<algorithm>

using namespace std;

 

#define N 110

#define MAX INT_MAX >> 1

#define CLR(arr, what) memset(arr, what,sizeof(arr))

 

int nodenum, edgenum;

int map[N][N], dis[N];

bool visit[N];

 

int SPFA(int src, int des)

{

   queue<int> q;

   CLR(visit, false);

   for(int i = 1;i <= nodenum; ++i)

       dis[i] = MAX;

   dis[src] = 0;

   visit[src] = true;

 

   q.push(src);

   while(!q.empty())

    {

       int cur = q.front();

       q.pop();

       visit[cur] = false; //出队标记为false

       for(int i = 1; i <= nodenum; ++i)

       {

           if(dis[i] > dis[cur] + map[cur][i]) //没有2个集合,和Dijkstra有本质区别

           {

                dis[i] = dis[cur] +map[cur][i]; //能松弛就松弛

                if(!visit[i]) //不在队列中则加入,然后更新所有以前经过此点的最短路径

                {

                    q.push(i);

                    visit[i] = true;

                }

           }

       }

    }

   return dis[des];

}

 

int main()

{

    intstart, end, cost;

    intanswer;

   while(~scanf("%d%d", &nodenum, &edgenum) &&(nodenum + edgenum))

    {

       for(int i = 1; i <= nodenum; ++i)

           for(int j = 1; j <= nodenum; ++j)

                map[i][j] = MAX;

       for(int i = 0; i < edgenum; ++i)

       {

           scanf("%d%d%d", &start, &end, &cost);

           if(cost < map[start][end])

                map[start][end] =map[end][start] = cost;

       }

       answer = SPFA(1, nodenum);

       printf("%d\n", answer);

    }

   return 0;

}

 

 

 

2、最小生成树:v + v + value布线问题完全路线

布线问题:由于安全问题,只能选择一个楼连接到外界供电设备。

引水工程:它们可以自建水库解决缺水问题

 

/*

1

V e

4 6

 

1 2 10

2 3 10

3 1 10

1 4 1

2 4 1

3 4 1

 

1 3 5 6

*/

 

#include<iostream>

using namespace std;

#define MAX 505

#define MAXCOST 0x7fffffff

 

int graph[MAX][MAX];

 

int prim(int graph[][MAX], int n)

{

         intlowcost[MAX];

         intmst[MAX];

         inti, j, min, minid, sum = 0;

         for(i = 2; i <= n; i++)

         {

                   lowcost[i]= graph[1][i];

                   mst[i]= 1;

         }

         mst[1]= 0;

         for(i = 2; i <= n; i++)

         {

                   min= MAXCOST;

                   minid= 0;

                   for(j = 2; j <= n; j++)

                   {

                            if(lowcost[j] < min && lowcost[j] != 0)

                            {

                                     min= lowcost[j];

                                     minid= j;

                            }

                   }

                   //cout<< "V" << mst[minid] << "-V" <<minid << "=" << min << endl;

                   sum+= min;

                   lowcost[minid]= 0;

                   for(j = 2; j <= n; j++)

                   {

                            if(graph[minid][j] < lowcost[j])

                            {

                                     lowcost[j]= graph[minid][j];

                                     mst[j]= minid;

                            }

                   }

         }

         returnsum;

}

 

int main()

{

         inti, j, k, m, n;

         intx, y, cost;

         intzushu;

         cin>>zushu;

         while(zushu--)

         {

             cin >> m >> n;//m=顶点的个数,n=边的个数

                   for(i = 1; i <= m; i++)

                   {

                            for(j = 1; j <= m; j++)

                            {

                                     graph[i][j]= MAXCOST;

                            }

                   }

                   for(k = 1; k <= n; k++)

                   {

                            cin>> i >> j >> cost;

                            graph[i][j]= cost;

                            graph[j][i]= cost;

                   }

             cost = prim(graph, m);

            

             int min_v=MAXCOST;

                   for(inti=1;i<=m;++i)

                   {

                            intt;

                       cin>>t;

                            if(t<min_v)

                            min_v=t;

                   }

                  

             cout <<cost+min_v<< endl;

         }

         return0;

}

 

-----------------------------------------------------------

 

3、最小生成树:v + v + value完全路线

/*

得到的统计表中列出了任意两村庄间的距离

3

1 2 1

1 3 2

2 3 4

4

1 2 1

1 3 4

1 4 1

2 3 3

2 4 2

3 4 5

0

*/

 

 

#include<iostream>

#include<cstdio>

using namespace std;

#define MAX 505

#define MAXCOST 0x7fffffff

 

int graph[MAX][MAX];

 

int prim(int graph[][MAX], int n)

{

         intlowcost[MAX];

         intmst[MAX];

         inti, j, min, minid, sum = 0;

         for(i = 2; i <= n; i++)

         {

                   lowcost[i]= graph[1][i];

                   mst[i]= 1;

         }

         mst[1]= 0;

         for(i = 2; i <= n; i++)

         {

                   min= MAXCOST;

                   minid= 0;

                   for(j = 2; j <= n; j++)

                   {

                            if(lowcost[j] < min && lowcost[j] != 0)

                            {

                                     min= lowcost[j];

                                     minid= j;

                            }

                   }

                   //cout<< "V" << mst[minid] << "-V" <<minid << "=" << min << endl;

                   sum+= min;

                   lowcost[minid]= 0;

                   for(j = 2; j <= n; j++)

                   {

                            if(graph[minid][j] < lowcost[j])

                            {

                                     lowcost[j]= graph[minid][j];

                                     mst[j]= minid;

                            }

                   }

         }

         returnsum;

}

 

int main()

{

         inti, j, k, m, n;

         intx, y, cost;

   

         while(scanf("%d",&m),m)

         {

                    //cin >> m >> n;//m=顶点的个数,n=边的个数

                    

                    n=(m*(m-1))/2;

                  

        

                   for(i = 1; i <= m; i++)

                   {

                            for(j = 1; j <= m; j++)

                            {

                                     graph[i][j]= MAXCOST;

                            }

                   }

                  

                   for(k = 1; k <= n; k++)

                   {

                            cin>> i >> j >> cost;

                            graph[i][j]= cost;

                            graph[j][i]= cost;

                   }

             cost = prim(graph, m);

             cout <<cost<< endl;

           

         }

             

         return0;

}              

 

4、prim算法之矩阵类型

/*

1

3(3*3的矩阵)

0 990 692

990 0 179

692 179 0

*/

#include "stdio.h"

#include "string.h"

#define N 500

#define INT 10000

bool vis[N];

int dis[N];

int a[N][N];

int main(){

         intt;

         scanf("%d",&t);

         while(t--){

                   intn;

                   scanf("%d",&n);

                   inti,j,temp,k;

                   memset(vis,0,sizeof(vis));

                   for(i=1;i<=n;++i){

                            for(j=1;j<=n;++j){

                                     scanf("%d",&a[i][j]);

                            }

                   }

                   for(i=1;i<=n;++i){

                            dis[i]=INT;

                   }

                   dis[1]=0;

                   for(i=1;i<=n;++i){

                            temp=INT;

                            k=0;

                            for(j=1;j<=n;++j){

                            if(!vis[j]&&dis[j]<temp){

                                     temp=dis[j];

                                     k=j;

                            }

                            }

                            vis[k]=1;

                            for(j=1;j<=n;++j){

                                     if(!vis[j]&&dis[j]>a[k][j]){

                                               dis[j]=a[k][j];

                                     }

                            }

                   }

                   intmax=0;

                   for(i=1;i<=n;++i){

                            if(max<dis[i])

                                     max=dis[i];

                   }

                   printf("%d\n",max);

         }

         return0;

}

 

5、输出最小生成树个边权值累加和(矩阵类型)

4

0 4 9 21

4 0 8 17

9 8 0 16

21 17 16 0

#include <stdio.h>

#include <string.h>

#define MaxInt 0x3f3f3f3f

#define N 110

int map[N][N],low[N],visited[N];

int n;

 

int prim()

{

    inti,j,pos,min,result=0;

   memset(visited,0,sizeof(visited));

   visited[1]=1;pos=1;

   for(i=1;i<=n;i++)

       if(i!=pos) low[i]=map[pos][i];

   for(i=1;i<n;i++)

    {

    min=MaxInt;

    for(j=1;j<=n;j++)

        if(visited[j]==0&&min>low[j])

        {

            min=low[j];pos=j;

        }

   result+=min;

   visited[pos]=1;

//更新权值

   for(j=1;j<=n;j++)

       if(visited[j]==0&&low[j]>map[pos][j])

           low[j]=map[pos][j];

    }

   return result;

}

 

int main()

{

    inti,v,j,ans;

   while(scanf("%d",&n)!=EOF)

    {

       memset(map,MaxInt,sizeof(map));

       for(i=1;i<=n;i++)

           for(j=1;j<=n;j++)

           {

                scanf("%d",&v);

                map[i][j]=map[i][j]=v;

           }

           ans=prim();

           printf("%d\n",ans);

    }

   return 0;

}

 

 

 

 

6、求出最小生成树中边的最大值(矩阵类型)

1

3

0 990 692

990 0 179

692 179 0

 

 

692

 

 

 

 

#include<stdio.h>

#define MAX 505

#define inf 999999

int c[MAX][MAX];

int n;

 

 

void prim()

{

    intlowcost[MAX ];

    intclosest[MAX ];

   bool s[MAX ];

   s[1]=true;

   for(int i=2;i<=n;i++)

    {

       lowcost[i]=c[1][i];

       closest[i]=1;

       s[i]=false;

    }

   for(int i=1;i<=n;i++)

    {

       int min=inf;

       int j=i;

       for(int k=2;k<=n;k++)

       if((lowcost[k]<min)&&(!s[k]))

       {

           min=lowcost[k];

            j=k;

       }

 

 

 

 

 

 

      //cout<<j<<" "<<closet[j]<<endl;输出最小生成树的路径。

 

 

       s[j]=true;

       for(int k=2;k<=n;k++)

       {

           if((c[j][k]<lowcost[k])&&(!s[k]))

           {

                lowcost[k]=c[j][k];

                closest[k]=j;

           }

       }

    }

 

 

 

 

//最小生成树的边值已经放大lowcost数组中了。遍历一下就可以得到最大最小值。

    intresult=-1;

   for(int i=2;i<=n;i++)

      {

          if(result<lowcost[i])

           result=lowcost[i];

      }

      printf("%d\n",result);

}

int main()

{

    intt;

   scanf("%d",&t);

   while(t--)

    {

       scanf("%d",&n);

       for(int i=1;i<=n;i++)

       {

           for(int  j=1;j<=n;j++)

           {

               scanf("%d",&c[i][j]);

           }

       }

       prim();

    }

   return 0;

}

 

 

 

 

7、prim算法变形之引水工程

 /*1

         5

  0 5 44 3 6

  5 0 22 2 2

  4  2 0 3 3 3

  4  2 3 0 4 5

  3  2 3 4 0 1

  5  2 3 5 1 0*/

#include <stdio.h>

#include <string.h>

#define MaxInt 0x3f3f3f3f

#define N 303

int map[N][N],low[N],visited[N];

int n;

 

int prim()

{

    inti,j,pos,min,result=0;

   memset(visited,0,sizeof(visited));

   visited[1]=1;pos=1;

   for(i=1;i<=n;i++)

       if(i!=pos) low[i]=map[pos][i];

   for(i=1;i<n;i++)

    {

    min=MaxInt;

     for(j=1;j<=n;j++)

        if(visited[j]==0&&min>low[j])

        {

            min=low[j];

                             pos=j;

        }

   result+=min;

   visited[pos]=1;

   for(j=1;j<=n;j++)

       if(visited[j]==0&&low[j]>map[pos][j])

           low[j]=map[pos][j];

    }

   return result;

}

 

int main()

{

    inti,v,j,ans,zushu;

   scanf("%d",&zushu);

    inta[303];

   while(zushu--)

    {

       

       scanf("%d",&n);

       memset(map,MaxInt,sizeof(map));

       

       map[1][1]=0;

       for(i=2;i<=n+1;++i)

       {

                 scanf("%d",&map[i][1]);

                 map[1][i]=map[i][1];

       }

      

       getchar();

       for(i=2;i<=n+1;i++)

           for(j=2;j<=n+1;j++)

           {

                scanf("%d",&v);

                map[i][j]=map[i][j]=v;

           }

           

       

       n=n+1;

        ans=prim();

          printf("%d\n",ans);

    }

   return 0;

}

 

 

       

8、Kruskal(克鲁斯卡尔)(不是完全边,v+v+value)

省政府“畅通工程”的目标是

 

使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。

现请你编写程序,计算出全省畅通需要的最低成本。

Input

测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N

行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。

为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。

Output

对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。

 

 

 

Sample Input

3 3

1 2 1

1 3 2

2 3 4

1 3

2 3 2

0 100

 

 

Sample Output

3

?

 

#include<iostream>

#include<cstring>

#include<string>

#include<cstdio>

#include<algorithm>

using namespace std;

#define MAX 100

int father[MAX], son[MAX];

int v, l;

 

typedef struct Kruskal //存储边的信息

{

         inta;

         intb;

         intvalue;

};

 

bool cmp(const Kruskal & a, const Kruskal& b)

{

         returna.value < b.value;

}

 

int unionsearch(int x) //查找根结点+路径压缩

{

         returnx == father[x] ? x : unionsearch(father[x]);

}

 

bool join(int x, int y) //合并

{

         introot1, root2;

         root1= unionsearch(x);

         root2= unionsearch(y);

         if(root1== root2) //为环

                   returnfalse;

         elseif(son[root1] >= son[root2])

                   {

                            father[root2]= root1;

                            son[root1]+= son[root2];

                   }

                   else

                   {

                            father[root1]= root2;

                            son[root2]+= son[root1];

                   }

         returntrue;

}

 

int main()

{

         intltotal, sum, flag;

         Kruskaledge[MAX];

         //scanf("%d",&ncase);

         while(scanf("%d%d",&l, &v),l)

         {

                   ltotal= 0, sum = 0, flag = 0;

                   for(inti = 1; i <= v; ++i) //初始化

                   {

                            father[i]= i;

                            son[i] = 1;

                   }

                   for(inti = 1; i <= l ; ++i)

                   {

                            scanf("%d%d%d",&edge[i].a, &edge[i].b, &edge[i].value);

                   }

                   sort(edge+ 1, edge + 1 + l, cmp); //按权值由小到大排序

                  

                   intcount=0;

                  

                   for(inti = 1; i <= l; ++i)

                   {

                            if(join(edge[i].a,edge[i].b))

                            {

                                     ltotal++;//边数加1

                                     sum+= edge[i].value; //记录权值之和

                                     //cout<<edge[i].a<<"->"<<edge[i].b<<endl;

                            }

                            if(ltotal== v - 1) //最小生成树条件:边数=顶点数-1

                            {

                                     flag= 1;

                                     break;

                            }

                            count++;

                   }

                    //printf("count%d\n", count);

                   if(flag)

                   printf("%d\n",sum);

                   else

                   printf("?\n");

                  

         }

         return0;

}

 

9、还差多少对v+v才能达到最小生成树

/*

 

目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,

只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

v e

 

4 2

1 3

4 3

 

3 3

1 2

1 3

2 3

 

5 2

1 2

3 5

 

999 0

0

输出最少还需要建设的道路数目。

*/

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<algorithm>

using namespace std;

int pre[1010];

 

int unionsearch(int root) //查找父节点+路径压缩(非递归)

{

    intson, tmp;

    son= root;

   while(root != pre[root])

       root = pre[root];

   while(son != root)

    {

       tmp = pre[son];

       pre[son] = root;

       son = tmp;

    }

   return root;

}

 

/*int unionsearch(int root) //查找父节点+路径压缩(递归)

{

         returnroot == pre[root] ? root : unionsearch(pre[root]);

}*/

 

int main()

{

    intnum, road, total, i, start, end, root1, root2;

   while(scanf("%d%d", &num, &road) && num)

    {

       total = num - 1;

       for(i = 1; i <= num; ++i)

           pre[i] = i;

       while(road--)

       {

           scanf("%d%d", &start, &end);

           root1 = unionsearch(start);

           root2 = unionsearch(end);

           if(root1 != root2)

           {

                pre[root1] = root2;

                total--;

           }

       }

       printf("%d\n", total);

    }

   return 0;

}

 

10、先判断是否畅通,再用最小生成树求最小花费

/*

对每个测试用例,在 1 行里输出全省畅通需要的最低成本。

若统计数据不足以保证畅通,则输出 No solution。

2

e v

3 3

1 2 1

1 3 2

2 3 4

 

 

1 3

2 3 2

样例输出

3

No solution

*/

 

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cmath>

#include<algorithm>

using namespace std;

//判断是否畅通

int pre[1010];

int unionsearch(int root) //查找父节点+路径压缩(非递归)

{

    intson, tmp;

    son= root;

   while(root != pre[root])

       root = pre[root];

   while(son != root)

    {

       tmp = pre[son];

       pre[son] = root;

       son = tmp;

    }

   return root;

}

//最小生成树

 

#define MAX 505

#define MAXCOST 0x7fffffff

int graph[MAX][MAX];

 

int prim(int graph[][MAX], int n)

{

         intlowcost[MAX];

         intmst[MAX];

         inti, j, min, minid, sum = 0;

         for(i = 2; i <= n; i++)

         {

                   lowcost[i]= graph[1][i];

                   mst[i]= 1;

         }

         mst[1]= 0;

         for(i = 2; i <= n; i++)

         {

                   min= MAXCOST;

                   minid= 0;

                   for(j = 2; j <= n; j++)

                   {

                            if(lowcost[j] < min && lowcost[j] != 0)

                            {

                                     min= lowcost[j];

                                     minid= j;

                            }

                   }

                   //cout<< "V" << mst[minid] << "-V" <<minid << "=" << min << endl;

                   sum+= min;

                   lowcost[minid]= 0;

                   for(j = 2; j <= n; j++)

                   {

                            if(graph[minid][j] < lowcost[j])

                            {

                                     lowcost[j]= graph[minid][j];

                                     mst[j]= minid;

                            }

                   }

         }

         returnsum;

}

 

int main()

{

    intnum, road, total, start, end, root1, root2;

   

    inti, j, k, m, n;

         intx, y, cost;

         intzushu;

         cin>>zushu;

        

         while(zushu--)

         {

             cin >>  n >> m ;//m=顶点的个数,n=边的个数

             num=m,road=n;

                  

                   for(i = 1; i <= m; i++)

                   {

                            for(j = 1; j <= m; j++)

                            {

                                     graph[i][j]= MAXCOST;

                            }

                   }

                  

                  

                   //------------判断是否畅通

             //num顶点,road道路

       total = num - 1;

       for(i = 1; i <= num; ++i)

           pre[i] = i;

           

           

                   for(k = 1; k <= n; k++)

                   {

               

以上是关于最小生成树次生成树最短路劲0-背包总结的主要内容,如果未能解决你的问题,请参考以下文章

生成树&最短路总结篇

经典树与图论(最小生成树、哈夫曼树、最短路径问题---Dijkstra算法)

刷题总结——次小生成树(bzoj1977 最小生成树+倍增)

习题—最小生成树单源最短路所有节点对最短路

prim算法(最小生成树)

次小生成树