1. 程式人生 > >vijos 1423 最短路or環(有向圖)

vijos 1423 最短路or環(有向圖)

取消 main 必須 測試 主辦方 marker ons eof eap

最佳路線

描述

年久失修的賽道令國際汽聯十分不滿。汽聯命令主辦方立即對賽道進行調整,否則將取消其主辦權。主辦方當然必須馬上開始行動。

賽道測評人員經過了三天三夜的數據采集,選出了若幹可以使用的道路和各道路行駛所需的時間。這些道路包括若幹直道和彎道,每個直道連接兩個不同的彎道且為單向,兩個彎道之間可能有多條直道,通過直道和彎道都需要一定的時間。主辦方打算在這些可用道路中選出一部分作為賽道。賽道是由直道和彎道交替組成的一圈,賽道可多次經過同一條彎道,因為主辦方可以通過架設立交橋的方法避免撞車。為了使比賽更加精彩,主辦方希望選擇一條單圈時間最短的賽道,由於觀眾席的位置在彎道1,所以賽道必須經過彎道1(賽道至少要包含一條直道)。

格式

輸入格式

第一行是兩個整數n,m(1<=n<=200,1<=m<=100000),分別表示彎道數和直道數。接下來n行,第i行是一個整數ai(1<=ai<=1000),表示通過第i個彎道所消耗的時間。接下來m行,第j行是三個整數xj,yj,bj(1<=xj,yj<=n,1<=bj<=1000),表示從彎道xj到彎道yj有一條單向直道,且通過該直道所消耗的時間為bj。

輸出格式

一個整數s,表示單圈時間最短的賽道的單圈時間,若無解則輸出-1。

樣例1

樣例輸入1

3 6
1
1
2
1 2 3
2 3 5
3 1 1
3 2 1
2 1 10
1 3 15
Copy

樣例輸出1

13
Copy

樣例2

樣例輸入2

3 4
1
1
2
1 2 4
1 3 5
2 3 5
3 2 10
Copy

樣例輸出2

-1
Copy

限制

各個測試點1s

此題是有向邊,且表明了1點一定在這個環中,youx兩種解法。

一是用floyd求環,由於是有向邊,所以不必擔心i-->j與j-->i會經過同一個點(反證法如果存在這個點k那麽顯然k點比j更優)

註意在建邊時把點權加在出度的邊上這樣求得的環的權值恰好正確;

所以可以先用floyd跑一下最短路,之後遍歷(2,n)找到最小值

:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f
int e[210][210];
int dis[210][210];
int w[210];
int main()
{
int n,m,i,j,k;
cin>>n>>m;
memset(e,inf,sizeof(e));
for(i=1;i<=n;++i) cin>>w[i],e[i][i]=0;
for(i=1;i<=m;++i){
int a,b,c;
cin>>a>>b>>c;
e[a][b]=min(e[a][b],c+w[a]);
}
for(k=1;k<=n;++k)
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
e[i][j]=min(e[i][j],e[i][k]+e[k][j]);
int ans=inf;
for(i=2;i<=n;++i) ans=min(ans,e[1][i]+e[i][1]);
printf("%d\n",ans==inf?-1:ans);
return 0;
}

也可以用dij跑最短路只不過我寫的前向星+heap兩者時間效率竟然一樣,但是數據大時floyd估計就gg了;

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
inline int read()
{
int r=0; char c=getchar();
while(c<‘0‘||c>‘9‘) c=getchar();
while(c>=‘0‘&&c<=‘9‘) r=r*10+c-‘0‘,c=getchar();
return r;
}
struct Heap
{
int u;
int w;
bool operator<(const Heap &chs)const{
return w>chs.w;}
};
struct Edge
{
int to;
int w;
int next;
}edges[100005];
int first[205];
int w[205];
int cnt,n;
int d[205];
bool vis[205];
void add(int a,int b,int c)
{
edges[cnt].w=c;
edges[cnt].to=b;
edges[cnt].next=first[a];
first[a]=cnt++;
}
int dij(int s,int e,int p)
{
memset(vis,0,sizeof(vis));
memset(d,inf,sizeof(d));
priority_queue<Heap> Q;
d[s]=0;
Q.push(Heap{s,0});
while(!Q.empty()){
Heap h=Q.top();Q.pop();
int u=h.u;
if(vis[u]) continue;
vis[u]=1;
if(u==e&&p==2) {return d[u];}
for(int i=first[u];i+1;i=edges[i].next){
Edge ee=edges[i];
if(d[ee.to]>d[u]+ee.w){
d[ee.to]=d[u]+ee.w;
Q.push(Heap{ee.to,d[ee.to]});
}
}
}
return inf;
}
int main()
{
int m,i,j,k;
int a,b,c;
int dd[205];
memset(first,-1,sizeof(first));
cnt=0;
cin>>n>>m;
for(i=1;i<=n;++i) w[i]=read();
for(i=1;i<=m;++i){
a=read(),b=read(),c=read();
add(a,b,c+w[a]);
} int ans=inf;
dij(1,1,1);
for(i=1;i<=n;++i) dd[i]=d[i];//,cout<<dd[i]<<endl;
//for(i=2;i<=n;++i)
//cout<<dij(i,1,2)<<endl;
for(i=2;i<=n;++i) ans=min(ans,dd[i]+dij(i,1,2));
printf("%d\n",(ans==inf?-1:ans));
return 0;
}

仔細想想的話,這只要跑一遍floyd最後e[1][1]中的就是答案,註意初始化全為inf即可(也可應用到求有向圖的最小環中)

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int e[210][210];
int w[210];
int main()
{
int n,m,i,j,k;
cin>>n>>m;
memset(e,inf,sizeof(e));
for(i=1;i<=n;++i) cin>>w[i];
for(i=1;i<=m;++i){
int a,b,c;
cin>>a>>b>>c;
e[a][b]=min(e[a][b],c+w[a]);
}int ans=inf;
for(k=1;k<=n;++k)
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
e[i][j]=min(e[i][j],e[i][k]+e[k][j]);
printf("%d\n",e[1][1]==inf?-1:e[1][1]);
return 0;
}

vijos 1423 最短路or環(有向圖)