1. 程式人生 > >vijos1423最佳路線——有向圖最小環模板

vijos1423最佳路線——有向圖最小環模板

題目:vijos1423.

題目大意:給定一些單向直道與彎道,並且給出每條單向直道連線哪兩條彎道,讓你求出經過彎道1的邊權最小的環.

這道題我們可以將彎道看成點,將直道看成有向邊,那麼原問題其實就是求經過點1的最小環.

解決最小環問題一般用的是floyd演算法或dijkstra演算法,這裡就給出一種堆優化dijkstra演算法解決這個問題.

首先我們可以想到,先將1定為原點,然後將1的距離定為0,1出堆後就將1的距離打上INF,然後知道下一次更新1的距離時,這個距離就是最小環的大小.

這種做法的正確性應該比較顯然.

程式碼如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=200,M=100000,INF=(1<<29)-1;
int n,m;
int dis[N+9],use[N+9],v[N+9];
struct node{
  int x,v;
  node(int xx,int vv){x=xx;v=vv;}
  bool operator > (const node &p)const{return v>p.v;}
};
priority_queue<node,vector<node>,greater<node> >q;
struct side{
  int y,next,v;
}e[M*2+9];
int lin[N+9],top;
void ins(int x,int y,int z){
  e[++top].y=y;e[top].v=z;e[top].next=lin[x];lin[x]=top;
}
void dijkstra(int s){
  for (int i=1;i<=n;i++)
    dis[i]=INF;
  int diss=INF;
  dis[s]=0;
  for (int i=lin[s];i;i=e[i].next)
    if (e[i].y==s){      //處理自環問題 
      if (diss>e[i].v+v[e[i].y]) diss=e[i].v+v[s];
    }else if (dis[s]+e[i].v+v[e[i].y]<dis[e[i].y]){
      dis[e[i].y]=dis[s]+e[i].v+v[e[i].y];
      q.push(node(e[i].y,dis[e[i].y]));
    }
  dis[s]=INF;
  while (!q.empty()){
    int t=q.top().x;q.pop();
    if (use[t]) continue;
    use[t]=1;
    for (int i=lin[t];i;i=e[i].next)
      if (dis[t]+e[i].v+v[e[i].y]<dis[e[i].y]){
      	dis[e[i].y]=dis[t]+e[i].v+v[e[i].y];
      	q.push(node(e[i].y,dis[e[i].y]));
      }
  }
  if (diss<dis[s]) dis[s]=diss;
}
Abigail into(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++)
    scanf("%d",&v[i]);
  int x,y,z;
  for (int i=1;i<=m;i++){
    scanf("%d%d%d",&x,&y,&z);
    ins(x,y,z);
  }
}
Abigail work(){
  dijkstra(1);
}
Abigail outo(){
  if (dis[1]>INF>>1) puts("-1");
  else printf("%d\n",dis[1]);
}
int main(){
  into();
  work();
  outo();
  return 0;
}