题意分析
1.任务
给出若干个木条的长度,求出不能围成的最大长度
有长度是一的都能围成
2.读入
n,m表示木条的种类和能切的长度
注意:x-d必须≥1
3.输出
无解(1.不存在,2.无限大)输出-1
有解输出
数据范围
1
算法分析
1.模拟
连续a[i]中的最小值
最短路
迪杰斯特拉算法
1.基本算法
Dijkstra算法是典型的 算法。 Dijkstra算法是很有代表性的 算法。Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用 OPEN, CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存在负权边。
2.权变的解释
按照这种算法来说,做这个程序应该是不难的,但有的时候会超时
这种算法支持多方位控制
注意啦!千万做这道题的时候不要尝试用prim做
以下可以帮助你理解
实现
- 将与源点相连的点加入 堆,并调整堆。
- 选出堆顶元素u(即代价最小的元素),从堆中删除,并对堆进行调整。
- 处理与u相邻的,未被访问过的,满足三角不等式的顶点
- 1):若该点在堆里,更新距离,并调整该元素在堆中的位置。
- 2):若该点不在堆里,加入堆,更新堆。
- 若取到的u为终点,结束算法;否则重复步骤2、3。
2.实现合并
做完的结果
看不到的点这:https://i.imgur.com/FDVYIxm.png
我们开始实现克里斯卡尔和迪杰斯特拉的合并啦!
我们首先要知道,这两个的算法其实是同一个思想的
++num;
data[num].x=x;
data[num].y=y;
data[num].z=z;
data[num].next=h[x];
h[x]=num;
++num;
data[num].x=y;
data[num].y=x;
data[num].z=z;
data[num].next=h[y];
h[y]=num;
这个,就是合并成功啦,我们需要在前面读入一些
scanf("%d%d",&t,&n);
num=0;
还有就是
memset(flag,false,sizeof flag);
flag[v]=true;
for(int j=h[v];j!=-1;j=data[j].next){
x=data[j].x; y=data[j].y; z=data[j].z;
if(!flag[y] and z+f[v]<f[y]){
f[y]=z+f[v];
}
}
3.读入什么
读入一个相对应的点
相对应点我点的强度为:父节点+权的强度=最后强度
结论克鲁斯卡尔的定义确实类似于迪杰斯特拉
最后附上程序
#include<cstdio>
#include<cstring>
struct node{
int x,y,z,next;
};
const int N1=1100;
const int N2=2200;
const int INF=0x7FFFFFFF;
bool flag[N1];
node data[N2*2];
int f[N1], h[N1];
int t,n,num,x,y,z,v;
int main(){
scanf("%d%d",&t,&n);
num=0;
memset(h,-1,sizeof h);
for(int i=1;i<=t;++i){
scanf("%d%d%d",&x,&y,&z);
++num;
data[num].x=x;
data[num].y=y;
data[num].z=z;
data[num].next=h[x];
h[x]=num;
++num;
data[num].x=y;
data[num].y=x;
data[num].z=z;
data[num].next=h[y];
h[y]=num;
}
memset(flag,false,sizeof flag);
for(int i=0;i<=n;++i)f[i]=INF;
f[1]=0;
for(int i=1;i<=n-1;++i){
v=0;
for(int j=1;j<=n;++j)if(!flag[j] and f[j]<f[v])
v=j;
flag[v]=true;
for(int j=h[v];j!=-1;j=data[j].next){
x=data[j].x; y=data[j].y; z=data[j].z;
if(!flag[y] and z+f[v]<f[y]){
f[y]=z+f[v];
}
}
}
printf("%d",f[n]);
return 0;
}