目录
算法
多源Floyed O(n*3)
原理:
利用三重循环,实时更新最短路径;
1.含义:
a【i】【j】:i--j 直接距离
a【i】【k】+ a【k】【j】:i--j 间接距离(经过k中转站)
2.解释:
求 i--j 的最短路径则讨论 i--j,i--1站点--j,i-2站点--j,i--3站点--j... ...
依次枚举比大小,实时更新
for(k=1; k<=n; k++) //依次枚举 1-n中转站,比大小
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
{
if(a[i][j]>a[i][k]+a[k][j])
a[i][j]=a[i][k]+a[k][j];
}
推导:
dijkstra--单源最短路径算法 O(n*2)
原理:
唯一起点到其他点的最短路径的算法,即单源最短路径算法
1.何为单源:
从同一起点出发到其他点,求1->2,1->3,1->4最短路径
2.含义:
dis【v】:表示某一固定点到第v点的最短路径的值
dis【u】: 表示前结点(已确定最短路径)的值
w【u】【v】:表示 u->v的距离
3.初始化:
起点s:dis【s】=0,其他点:dis【v】=∞;
4.核心:从最短距离开始找(找最小边kruskal算法)+更新dis【】数组
①从最小距离开始,再次小距离... ...
for(int i=1;i<=n;i++)
{ if(!book[i]&&minn>dis[i])
{ minn=dis[i]; //从未标记中找最小距离及其下标
t=i; }
}②最初的dis【v】:为1--v的直接距离;
更新的dis【v】:为1--v的间接距离;
if (dis【u】+ w【u】【v】< dis【v】)
{ dis【v】=dis【u】+ w【u】【v】; }
即最终dis【v】为最短路径;
//a【i】【j】:存储已知i->j的距离
//dis【t】:定点s到t的最短距离
void dijk(int s)
{
memset(book,0,sizeof(book));
memset(dis,999999,sizeof(dis));
dis[s]=0;
while(1)
{
int t=0,minn=999999;
for(int i=1;i<=n;i++)
{
if(!book[i]&&minn>dis[i])
{
minn=dis[i]; //从未标记中找最小距离及其下标
t=i;
}
}
book[t]=1; //标记t点,进入以下循环
if(t==0) break; //点全被标记,跳出循环
for(int i=1;i<=n;i++) //更新dis【】最短路径数组
{
if(dis[i]>dis[t]+a[t][i]) //dis【】为s点直接到i点的距离
dis[i]=dis[t]+a[t][i]; //dis[t]+a[t][i]为s点经过t点到达i点的间接距离
}
}
}
刷题
1.租用游艇
P1359 租用游艇 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
https://www.luogu.com.cn/problem/P1359
1.格式化输入二维数组:1-2,1-3,1-4,2-3,2-4,3-4... ...
for(int i=1; i<=n-1; i++)
for(int j=i+1; j<=n; j++)2.三重for循环枚举路径:第一层for枚举1-k中转站,第二,三层为 i站点--j站点直达所需距离
3.输出1-n(a[1][n])的最短路径:有序!1-n ≠ n-1
#include<stdio.h>
#include<string.h>
int main()
{
int n,a[210][210];
scanf("%d",&n);
memset(a,1,sizeof(a)); //数组初值赋大数
for(int i=1; i<=n-1; i++) //注意输入格式
{
for(int j=i+1; j<=n; j++)
{
scanf("%d",&a[i][j]);
}
}
for(int k=1; k<=n; k++) //枚举1-k中转站
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(a[i][j]>a[i][k]+a[k][j])
{
a[i][j]=a[i][k]+a[k][j];
}
}
}
}
printf("%d",a[1][n]); //1-n的最短路径
}
2.修路
1.变量设置:结构体存储:点1+点2+1到2的距离
2.初始化&&找find father:并查集基本操作
3.升序排序距离:调用库函数,快排不行
4.unionn时加入权值(距离):
5.终止条件:sum==n-1,线全部用完
6.注意:条件已知已连接点点,两点距离设为0即可
#include<bits/stdc++.h>
using namespace std;
int fa[500501];
long double ans=0.0;
int sum=0;
int k=0;
struct node
{
int x,y;
double z;
} a[500501];
void init(int n)
{
for(int i=1; i<=n; i++)
{
fa[i]=i;
}
}
int find(int i)
{
if(fa[i]==i) return i;
else
{
return find(fa[i]);
}
}
/*void quick(int left,int right)
{
int i=left,j=right;
struct node t,temp;
temp=a[left];
while(i!=j)
{
while(i<j&&a[j].z>=temp.z)
{
j--;
}
while(i<j&&a[i].z<=temp.z)
{
i++;
}
if(i<j)
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
a[left]=a[i];
a[i]=temp;
quick(left,i-1);
quick(j+1,right);
}
*/
bool cmp(node a,node b)
{
return a.z<b.z;
}
void add(int i,int j,double l) //构造结构体存储两点间距离(点+点+距离)
{
a[++k].x=i;
a[k].y=j;
a[k].z=l;
}
int main()
{
int i,j,m,n,b,c;
int xx[500501],yy[500501];
scanf("%d %d",&n,&m);
init(n);
for(i=1; i<=n; i++)
{
scanf("%d %d",&xx[i],&yy[i]);
}
for(i=1; i<=n; i++)
for(j=i+1; j<=n; j++)
{
long double z=(double)sqrt((double)(xx[i]-xx[j])*(xx[i]-xx[j])+(double)(yy[i]-yy[j])*(yy[i]-yy[j]));
add(i,j,z);
}
for(i=1; i<=m; i++)
{
scanf("%d %d",&b,&c);
add(b,c,0.0);
}
//quick(1,k);
sort(a+1,a+1+k,cmp);
for(i=1; i<=k; i++)
{
int x=find(a[i].x);
int y=find(a[i].y);
if(x!=y)
{
fa[x]=y;
sum++; //线使用量+1
ans+=a[i].z; //权值求和
}
if(sum==n-1) break; //n为点个数,n-1为线个数
}
printf("%.2Lf",ans);
return 0;
}