kuangbin带你飞:点击进入新世界
最短路算法模板:点击进入新世界
本人算是初学者中的初学者,欢迎交流~
kuangbin的专题确实是理解最短路的一大途径,这篇博客主要记录题解,顺便总结最短路的题型。
A.模板题 参考1 . 6 . 10
B.变形最短路 (求最大边权的最小值or最小边权的最大值) 参考2 . 3
C.变形最短路 (求往返最短路的最大值) 参考4
D.变形最短路 (求往返最短路之和) 参考5
E.含负权边的最短路 (spfa判负环) 参考 7 . 11 . 12
F. 确定排名 参考8
G.差分约束系统 (<=最短路 and >=最长路) 参考9 . 11
ps:跑最短路求得就是最大的距离,跑最长路求的就是最小的距离
H.判正环 参考 13 . 14
差分约束系统介绍
最短路其实不难,难点在于建图,剩下五道题没灵感,等国庆后补。
kuangbin之外:
最短路计数
最短路+二分
最短路+dp
分层图最短路
原题链接:传送门
思路:
#include
#include
#include
#include
#include
#define R register int
using namespace std;
const int manx=1e4+5;
const int mamx=1e4+5;
int head[manx],d[manx];
bool vis[manx];
int n,m,k=0,s,e;
struct node{
int v,next,w;
}a[manx];
void add(int u,int v,int w)
{
a[++k].next=head[u];
a[k].w=w;
a[k].v=v;
head[u]=k;
}
void dij()
{
memset(d,0x3f,sizeof(d));
memset(vis,0,sizeof(vis));
d[s]=0;
priority_queue<pair<int,int> >q;
q.push(make_pair(0,s));
while(q.size()){
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=a[i].next){
int v=a[i].v,w=a[i].w;
if(d[v]>d[u]+w) d[v]=d[u]+w,q.push(make_pair(-d[v],v));
}
}
}
int main()
{
scanf("%d%d",&m,&n);
e=1,s=n;
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dij();
cout<<d[e];
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
using namespace std;
const int manx=300;
int x[manx],y[manx];
double d[manx][manx];
int main()
{
int n,m,f=1;
while(scanf("%d",&n)!=EOF&&n)
{
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
d[i][j]=d[j][i]=sqrt(pow((x[i]-x[j])*1.0,2)+pow((y[i]-y[j])*1.0,2));
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=min(d[i][j],max(d[i][k],d[k][j]));
cout<<"Scenario #"<<f++<<endl;
printf("Frog Distance = %.3lf\n\n",d[1][2]);
}
return 0;
}
原题链接:传送门
思路:
AC代码如下:
#include
#include
#include
#include
#include
using namespace std;
const int manx=1e6+5;
const int mamx=1e6+5;
int head[manx],d[manx];
bool vis[manx];
struct node{
int v,w,next;
}a[mamx];
int n,m,s,e,k=0;
void add(int u,int v,int w)
{
a[++k].next=head[u];
a[k].w=w;
a[k].v=v;
head[u]=k;
}
void spfa()
{
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
d[s]=1e9;
queue<int>q;
q.push(s);
while(q.size())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=a[i].next)
{
int v=a[i].v,w=a[i].w;
if(d[v]<min(d[u],w)) {
d[v]=min(d[u],w);
if(!vis[v])
q.push(v),vis[v]=1;
}
}
}
}
int main()
{
int t;
cin>>t;
for(int o=1;o<=t;o++)
{
scanf("%d%d",&n,&m);
s=1,e=n,k=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
spfa();
printf("Scenario #%d:\n",o);
printf("%d\n",d[e]);
printf("\n");
}
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
using namespace std;
const int manx=1e3+5;
const int mamx=1e6+5;
struct node{
int v,next,w;
}a[mamx];
int d[manx][manx],head[manx];
bool vis[manx];
int n,m,s,e,k=0;
void add(int u,int v,int w)
{
a[++k].next=head[u];
head[u]=k;
a[k].v=v;
a[k].w=w;
}
void dij()
{
for(int i=1;i<=n;i++) d[s][i]=1e9;
memset(vis,0,sizeof(vis));
priority_queue<pair<int,int> >q;
d[s][s]=0;
q.push(make_pair(0,s));
while(q.size()){
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=a[i].next)
{
int v=a[i].v,w=a[i].w;
if(d[s][v]>d[s][u]+w)
d[s][v]=d[s][u]+w,q.push(make_pair(-d[s][v],v));
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&e);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
for(int i=1;i<=n;i++) s=i,dij();
int ans=-1;
for(int i=1;i<=n;i++){
if(i==e) continue;
if(ans<d[i][e]+d[e][i])
ans=d[i][e]+d[e][i];
}
cout<<ans<<endl;
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
using namespace std;
const int manx=1000000+5;
const int mamx=manx;
struct node{
int v,next,w;
}a[2][mamx];
int d[2][manx],head[2][manx];
bool vis[manx];
int n,m,s,e,k0=0,k1=0;
void add(int i,int u,int v,int w)
{
int k;
if(i==0) k=k0; else k=k1;
a[i][++k].next=head[i][u];
head[i][u]=k;
a[i][k].v=v;
a[i][k].w=w;
if(i==0) k0=k; else k1=k;
}
void dij(int x)
{
for(int i=1;i<=n;i++) d[x][i]=1e9;
memset(vis,0,sizeof(vis));
priority_queue<pair<int,int> >q;
d[x][1]=0;
q.push(make_pair(0,1));
while(q.size()){
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[x][u];i;i=a[x][i].next)
{
int v=a[x][i].v,w=a[x][i].w;
if(d[x][v]>d[x][u]+w)
d[x][v]=d[x][u]+w,q.push(make_pair(-d[x][v],v));
}
}
}
int main()
{
int t;
cin>>t;
while(t--)
{
k0=0,k1=0;
memset(head,0,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(0,u,v,w);
add(1,v,u,w);
}
dij(0),dij(1);
long long ans=0;
for(int i=2;i<=n;i++){
ans+=d[0][i]+d[1][i];
}
cout<<ans<<endl;
}
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
using namespace std;
const int manx=1e3+5;
const int mamx=1e5+5;
int head[manx],d[manx];
bool vis[manx];
struct node{
int v,w,next;
}a[mamx];
priority_queue<pair<int,int> >q;
int k=0,n,m,s,e;
void add(int u,int v ,int w)
{
a[++k].next=head[u];
a[k].v=v;
a[k].w=w;
head[u]=k;
}
void dij()
{
for(int i=1;i<=n;i++) d[i]=1e9;
d[s]=0;
q.push(make_pair(0,s));
while(q.size())
{
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=a[i].next)
{
int v=a[i].v,w=a[i].w;
if(d[v]>d[u]+w&&!vis[v]) d[v]=d[u]+w,q.push(make_pair(-d[v],v));
}
}
}
int main()
{
scanf("%d%d%d",&n,&s,&e);
for(int i=1;i<=n;i++)
{
scanf("%d",&m);
for(int j=1;j<=m;j++)
{
int v;
scanf("%d",&v);
if(j==1) add(i,v,0);
else add(i,v,1);
}
}
dij();
if(d[e]==1e9) cout<<"-1"<<endl;
else cout<<d[e]<<endl;
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
using namespace std;
const int manx=1e3+5;
const int mamx=1e6+5;
struct node{
int v,next,w;
}a[mamx];
int d[manx],head[manx],f[manx];
bool vis[manx];
int n,m,s,e,k=0;
void add(int u,int v,int w)
{
a[++k].next=head[u];
head[u]=k;
a[k].v=v;
a[k].w=w;
}
bool spfa()
{
for(int i=1;i<=n;i++) d[i]=1e9,f[i]=0;
memset(vis,0,sizeof(vis));
queue<int>q;
d[1]=0;
f[1]=1;
q.push(1);
while(q.size()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=a[i].next)
{
int v=a[i].v,w=a[i].w;
if(d[v]>d[u]+w){
d[v]=d[u]+w;
if(!vis[v]){
f[v]++;
if(f[v]>=n) return false;
q.push(v);
vis[v]=1;
}
}
}
}
return true;
}
int main()
{
int o;
cin>>o;
while(o--){
memset(head,0,sizeof(head));
scanf("%d%d%d",&n,&m,&e);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
for(int i=1;i<=e;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,-w);
}
if(spfa()) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
using namespace std;
const int manx=1e2+5;
const int mamx=4e5+5;
struct node{
int v,next,w;
}a[mamx];
int d[manx][manx],head[manx],f[manx];
bool vis[manx];
int n,m,s,e,k=0;
void add(int u,int v,int w)
{
a[++k].next=head[u];
head[u]=k;
a[k].v=v;
a[k].w=w;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
d[u][v]=1;
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(d[i][k]&&d[k][j])
d[i][j]=1;
int ans=0;
for(int i=1;i<=n;i++)
{
int res=0;
for(int j=1;j<=n;j++)
if(d[i][j]||d[j][i]) res++;
if(res==n-1) ans++;
}
cout<<ans<<endl;
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
using namespace std;
const int manx=3e5+5;;
const int mamx=3e6+5;
int head[manx],d[manx];
bool vis[manx];
int n,m,k=0,s,e;
struct node{
int v,next,w;
}a[manx];
void add(int u,int v,int w)
{
a[++k].next=head[u];
a[k].w=w;
a[k].v=v;
head[u]=k;
}
void dij()
{
memset(d,0x3f,sizeof(d));
memset(vis,0,sizeof(vis));
d[s]=0;
priority_queue<pair<int,int> >q;
q.push(make_pair(0,s));
while(q.size()){
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=a[i].next){
int v=a[i].v,w=a[i].w;
if(d[v]>d[u]+w) d[v]=d[u]+w,q.push(make_pair(-d[v],v));
}
}
}
int main()
{
scanf("%d%d",&n,&m);
e=n,s=1;
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
dij();
cout<<d[e];
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
#define inf 0x3f3f3f
using namespace std;
const int manx=300;
int d[manx][manx];
int main()
{
int n,m;
char s[12];
while(scanf("%d",&n)!=EOF&&n)
{
memset(d,inf,sizeof(d));
for(int i=1;i<=n;i++) d[i][i]=0;
for(int i=2;i<=n;i++)
for(int j=1;j<i;j++)
{
cin>>s;
if(s[0]=='x') continue;
d[i][j]=d[j][i]=atoi(s);
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
int ans=-1;
for(int i=2;i<=n;i++) if(d[1][i]!=inf) ans=max(ans,d[1][i]);
cout<<ans<<endl;
}
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
using namespace std;
const int manx=1e3+5;
const int mamx=1e6+5;
struct node{
int v,next,w;
}a[mamx];
int d[manx],head[manx],f[manx];
bool vis[manx];
int n,m,s,e,k=0;
void add(int u,int v,int w)
{
a[++k].next=head[u];
head[u]=k;
a[k].v=v;
a[k].w=w;
}
void spfa()
{
for(int i=1;i<=n;i++) d[i]=1e9,f[i]=0;
memset(vis,0,sizeof(vis));
queue<int>q;
d[1]=0;
f[1]=1;
q.push(1);
while(q.size()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=a[i].next)
{
int v=a[i].v,w=a[i].w;
if(d[v]>d[u]+w){
d[v]=d[u]+w;
if(!vis[v]){
f[v]++;
if(f[v]>n){
cout<<"-1"<<endl;
return;
}
q.push(v);
vis[v]=1;
}
}
}
}
if(d[n]==1e9) cout<<"-2"<<endl;
else cout<<d[n]<<endl;
return ;
}
int main()
{
scanf("%d%d%d",&n,&m,&e);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
for(int i=1;i<=e;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(v,u,-w);
}
spfa();
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
#define inf 0x3f3f3f3f
using namespace std;
const int manx=1e3+5;
const int mamx=1e6+5;
struct node{
int v,next,w;
}a[mamx];
int d[manx],head[manx],f[manx],ff[manx];
bool vis[manx];
int n,m,s,e,k=0;
void add(int u,int v,int w)
{
a[++k].next=head[u];
head[u]=k;
a[k].v=v;
a[k].w=w;
}
void spfa()
{
memset(ff,0,sizeof(ff));
memset(d,inf,sizeof(d));
memset(vis,0,sizeof(vis));
queue<int>q;
d[1]=0;
ff[1]=1;
q.push(1);
while(q.size()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=a[i].next)
{
int v=a[i].v,w=a[i].w;
if(d[v]>d[u]+w){
d[v]=d[u]+w;
if(!vis[v]&&ff[v]<=n){ //当ff[v]入队次数不大于n才进入if里面
ff[v]++;
q.push(v);
vis[v]=1;
}
}
}
}
}
int main()
{
int o,oo=1;
cin>>o;
while(o--)
{
memset(head,0,sizeof(head));
k=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&f[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d",&u,&v);
w=int(pow(f[v]-f[u],3));
add(u,v,w);
}
spfa();
scanf("%d",&s);
printf("Case %d:\n",oo++);
while(s--)
{
scanf("%d",&e);
if(ff[e]>n||d[e]<3||d[e]==inf) printf("?\n");
else printf("%d\n",d[e]);
}
}
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
#define inf 0x3f3f3f3f
using namespace std;
const int manx=300;
const int mamx=300;
double d[manx];
int f[manx],head[manx];
bool vis[manx];
int n,m,s,k=0;
double g;
struct node{
int v,next;
double f1,f2;
}a[mamx];
void add(int u,int v,double f1,double f2)
{
a[++k].next=head[u];
head[u]=k;
a[k].f1=f1;
a[k].f2=f2;
a[k].v=v;
}
bool spfa()
{
memset(d,0,sizeof(d));
memset(f,0,sizeof(f));
memset(vis,0,sizeof(vis));
d[s]=g;
queue<int>q;
q.push(s);
f[s]++;
while(q.size())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=a[i].next)
{
int v=a[i].v;
double val=(d[u]-a[i].f2)*a[i].f1;
if(d[v]<val){
d[v]=val;
if(!vis[v]){
vis[v]=1;
f[v]++;
q.push(v);
if(f[v]>n) return 1;
}
}
}
}
if(d[s]>g) return 1; //即便没有正环 看跑完起点的货币是否增值
return 0;
}
int main()
{
while(scanf("%d%d%d%lf",&n,&m,&s,&g)!=EOF)
{
k=0;
memset(head,0,sizeof(head));
for(int i=1;i<=m;i++)
{
int u,v;
double x,y;
scanf("%d%d",&u,&v);
scanf("%lf%lf",&x,&y);
add(u,v,x,y);
scanf("%lf%lf",&x,&y);
add(v,u,x,y);
}
if(spfa()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
原题链接:传送门
思路:
AC代码如下:
// #include
#include
#include
#include
#include
#include
#include
#include
#include
#define R register int
#define mm make_pair
#define inf 0x3f3f3f3f
using namespace std;
const int manx=100;
int n,m;
string s;
map<string,int>q;
double d[manx][manx];
int main()
{
int haha=1;
while(scanf("%d",&n)!=EOF&&n)
{
memset(d,0.0,sizeof(d));
q.clear();
for(int i=1;i<=n;i++) d[i][i]=1.0;
for(int i=1;i<=n;i++) cin>>s,q[s]=i;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
string u,v;
double w;
cin>>u>>w>>v;
int x,y;
x=q[u],y=q[v];
d[x][y]=max(d[x][y],w);
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=max(d[i][j],d[i][k]*d[k][j]);
int flag=1;
for(int i=1;i<=n;i++)
if(d[i][i]>1)
flag=0;
if(!flag) printf("Case %d: Yes\n",haha++);
else printf("Case %d: No\n",haha++);
}
return 0;
}