版权声明:转载请注明出处 https://blog.csdn.net/qq_39541141/article/details/83719683
最近系统的(重新)复习了一下最短路
毕竟许多题都可以转化成最短路来写
先说一下Folyed()
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
这个算法的思路显而易见 这里不再赘述
拓展
当该图为无向图时
我们可以这么写
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
a[j][i]=a[i][j]=min(a[i][j],a[i][k]+a[k][j]);
这个比上面那个快一倍吧
在 P1828 香甜的黄油 Sweet Butter里加上这个优化就可以过QAQ
代码如下
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int f[804][804],a[804][804],m,n,c[888],p,x,y,z,temp,ans=999999;
inline int read()
{
int f=1,w=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while('0'<=ch&&ch<='9'){w=w*10+ch-48;ch=getchar();}
return f*w;
}
int main()
{
cin>>p>>n>>m;
for(int i=1;i<=n;i++)
for(int l=1;l<=n;l++)
{
if(i==l)f[i][l]=a[i][l]=0;
else f[i][l]=a[i][l]=999999;
}
for(int i=1;i<=p;i++)
c[i]=read();
for(register int l=1;l<=m;l++){
x=read(),y=read(),z=read();
a[y][x]=a[x][y]=z;
f[y][x]=f[x][y]=z;
}
for(register int i=1;i<=n;i++)
for(register int l=1;l<=n;l++)
for(register int j=1;j<=l;j++)
f[l][j]=f[j][l]=min(f[j][l],f[j][i]+f[i][l]);
for(register int i=1;i<=n;i++)
{
temp=0;
for(register int l=1;l<=p;l++)
temp+=f[i][c[l]];
ans=min(ans,temp);
}
cout<<ans<<endl;
return 0;
}
拓展×2
如果这张图是用坐标表示的
比如这道题吧 古韵之鹊桥相会
建图之后就用以下这种folyed去找
#include <bits/stdc++.h>
using namespace std;
const int maxn = 25, INF = 0x3f3f3f3f;
string s[maxn];
int n, m, res = INF, dp[maxn][maxn][maxn][maxn];
int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
int main() {
ios::sync_with_stdio(false);
memset(dp, INF, sizeof(dp));
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> s[i];
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
dp[i][j][i][j] = 0;
for (int k = 0; k < 4; k++) {
int x = i + dx[k], y = j + dy[k];
if (x >= 0 && x < n && y >= 0 && y < m) {
dp[i][j][x][y] = (s[i][j] != s[x][y]);
}
}
}
}
// floyd
for (int kx = 0; kx < n; kx++) {
for (int ky = 0; ky < m; ky++) {
for (int ix = 0; ix < n; ix++) {
for (int iy = 0; iy < m; iy++) {
for (int jx = 0; jx < n; jx++) {
for (int jy = 0; jy < m; jy++) {
dp[ix][iy][jx][jy] = min(dp[ix][iy][jx][jy], dp[ix][iy][kx][ky] + dp[kx][ky][jx][jy]);
}
}
}
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
res = min(res, dp[0][i][n - 1][j]);
}
}
cout << res + 1 << endl;
return 0;
}
(不是我的代码QAQ 在题解里面翻了一个)
也也也应该就这些了吧(我就知道这些)
Dijkstra(n log n)
终于该讲这个了QAQ
Dijkstra是目前跑的最快的单源最短路算法。
Dijkstra的适用范围:没有负权边的图。
代码如下(怎么又不讲代码???? 我我我也不会讲吖)
#include<iostream>
#include<algorithm>
#include<queue>
#define maxn 100002
#define maxm 200002
using namespace std;
int head[maxn],next[maxm],to[maxm],d[maxn],w[maxm],tot,s,n;
bool v[maxn];
priority_queue<pair<int,int> >q;
inline void add(int x,int y,int z){
next[++tot]=head[x],head[x]=tot;
to[tot]=y,w[tot]=z;
}
void dijkstra(){
for(register int i=1;i<=n;i++)d[i]=1e10;
d[s]=0;q.push(make_pair(d[s],s));
while(!q.empty()){
int x=q.top().second;q.pop();
if(v[x])continue; v[x]=1;
for(register int i=head[x];i;i=next[i]){
int y=to[i],z=w[i];
if(d[y]>d[x]+z)
d[y]=d[x]+z,q.push(make_pair(-d[y],y));
}
}
}
int main()
{
int m,x,y,z;
cin>>n>>m>>s;
for(register int i=1;i<=m;i++){
cin>>x>>y>>z;
add(x,y,z);
}
dijkstra();
for(register int i=1;i<=n;i++)cout<<d[i]<<" ";
return 0;
}
拓展
如何求出最短路径有几条?
加一个语句就ok 见P1144 最短路计数
#include<iostream>
#include<queue>
#define maxn 1000002
#define maxm 2000002
using namespace std;
priority_queue<pair<int ,int> >q;
int next[maxm],head[maxn],to[maxm],w[maxm],dis[maxn],cnt,ans[maxm];
bool v[maxm];
inline void add(int x,int y){
next[++cnt]=head[x],head[x]=cnt;
to[cnt]=y,w[cnt]=1;
}
int main()
{
int m,n,s=1,x,y,z;
cin>>n>>m;
for(register int i=1;i<=n;i++)dis[i]=1e10;
for(register int i=1;i<=m;i++)
{cin>>x>>y;add(x,y);add(y,x);}
ans[s]=1,dis[s]=0,q.push(make_pair(0,s));//多了一个初始化
while(!q.empty()){
int x=q.top().second;q.pop();
if(v[x])continue ;v[x]=1;
for(register int i=head[x];i;i=next[i]){
int y=to[i],z=w[i];
if(dis[y]>z+dis[x]){
dis[y]=dis[x]+z;
ans[y]=ans[x];//更新最短路同时也更新路径数量
q.push(make_pair(-dis[y],y));
}
//增加路径
else if(dis[y]==dis[x]+1){
ans[y]+=ans[x];
ans[y]%=100003;
}
}
}
for(register int i=1;i<=n;i++)cout<<ans[i]<<endl;
return 0;
}
(也就是改了改上面的代码)
拓展×2
怎样输出路径???
也是加上几条语句
代码如下
#include<iostream>
#include<algorithm>
#include<queue>
#define maxn 100002
#define maxm 200002
using namespace std;
int head[maxn],next[maxm],to[maxm],d[maxn],w[maxm],tot,s,n;
int road[1003][1003];
bool v[maxn];
priority_queue<pair<int,int> >q;
inline void add(int x,int y,int z){
next[++tot]=head[x],head[x]=tot;
to[tot]=y,w[tot]=z;
}
void dijkstra(){
for(register int i=1;i<=n;i++)d[i]=1e10;
d[s]=0;q.push(make_pair(d[s],s));
while(!q.empty()){
int x=q.top().second;q.pop();
if(v[x])continue; v[x]=1;
for(register int i=head[x];i;i=next[i]){
int y=to[i],z=w[i];
if(d[y]>d[x]+z){
d[y]=d[x]+z;
road[s][y]=road[x][y];//更新前驱点
q.push(make_pair(-d[y],y));
}
}
}
}
inline void prin(int x){
if(road[s][x]==0)return ;
prin(road[s][x]);
cout<<"->"<<x;
}
int main()
{
int m,x,y,z;
cin>>n>>m>>s;
for(register int i=1;i<=m;i++){
cin>>x>>y>>z;
add(x,y,z);
road[x][y]=x;//从x到y的前驱点是x
}
dijkstra();
for(register int i=1;i<=n;i++){
cout<<d[i]<<" ";
if(d[i])cout<<s,prin(i);
cout<<endl;
}
return 0;
}
嗯......
先到这里吧