1. 程式人生 > >【NOIP2009提高】藍書(演算法競賽進階指南)刷題記錄——luogu1037最優貿易

【NOIP2009提高】藍書(演算法競賽進階指南)刷題記錄——luogu1037最優貿易

題目:給出一張圖,求出兩個點p和q的點權差(一定是p-q)最大,且從點p一定要能便利到點q.

解法一:

這道題我們若是一張有向無環圖的話,我們可以直接跑一個DP,其中推出一個dis0[i]表示從點1到點i的點權最小值,dis1[i]表示從點i到點n上的點權最大值,然後暴力枚舉出最大的dis1[i]-dis0[i].

當有環時,我們可以用最短路代替DP,同樣也是跑dis1和dis0,然後暴力枚舉出答案.用spfa時間複雜度為O(tn),用堆優化dijkstra時間複雜度為O(n+mlogm).

由於一開始覺得自己dijkstra寫的沒有spfa熟,就想寫個堆優化spfa的,然後突然發現還是堆優化dijkstra好寫,就沒改函式名...

程式碼如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000,M=500000;
const int INF=(1<<30)-1;
struct side{
  int y,next;
}e[M*4+9];
int lin[N+9][2],top;
int n,m,v[N+9];
int dis0[N+9],dis1[N+9],ans;
bool use[N+9];
struct node{
  int x,v;
  bool operator <(node p)const{
  	return v<p.v;
  }
  bool operator >(node p)const{
    return v>p.v;
  }
  node(int xx,int vv){
    x=xx;v=vv;
  }
};
priority_queue<node> qmax;
priority_queue<node,vector<node>,greater<node> > qmin;
void ins(int t,int x,int y){
  e[++top].y=y;
  e[top].next=lin[x][t];
  lin[x][t]=top;
}
void spfa0(int sx){
  for (int i=1;i<=n;i++)
    dis0[i]=INF,use[i]=0;
  qmin.push(node(sx,v[sx]));
  dis0[sx]=v[sx];
  while (!qmin.empty()){
    node t=qmin.top();qmin.pop();
    if (use[t.x]) continue;
    use[t.x]=1;
    for (int i=lin[t.x][0];i;i=e[i].next){
      if (min(t.v,v[e[i].y])<dis0[e[i].y]){
        dis0[e[i].y]=min(dis0[t.x],v[e[i].y]);
        qmin.push(node(e[i].y,dis0[e[i].y]));
      }
    }
  }
}
void spfa1(int sx){
  for (int i=1;i<=n;i++)
    dis1[i]=-INF,use[i]=0;
  qmax.push(node(sx,v[sx]));
  dis1[sx]=v[sx];
  while (!qmax.empty()){
    node t=qmax.top();qmax.pop();
    if (use[t.x]) continue;
    use[t.x]=1;
    for (int i=lin[t.x][1];i;i=e[i].next)
      if (max(t.v,v[e[i].y])>dis1[e[i].y]){
        dis1[e[i].y]=max(dis1[t.x],v[e[i].y]);
        qmax.push(node(e[i].y,dis1[e[i].y]));
      }
  }
}
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(0,x,y);ins(1,y,x);
    if (z==1) continue;
    ins(0,y,x);ins(1,x,y);
  }
}
Abigail work(){
  spfa0(1);
  spfa1(n);
  for (int i=1;i<=n;i++)
    ans=max(ans,dis1[i]-dis0[i]);
}
Abigail outo(){
  printf("%d\n",ans);
}
int main(){
  into();
  work();
  outo();
  return 0;
}