最小生成树次生成树最短路劲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算法)