1. 程式人生 > >尋找道路 & 最優貿易

尋找道路 & 最優貿易

兩道題目都很有意思,都不難但需要開動腦筋去仔細想想;

先說最優貿易,只買一次,賣一次,簡化一下題目就是在某個點值
與其之前的所有點的最小的差最大是多少,這樣就可以看到一個是之前的最小,一個是之後的最大,我們可以考慮如何找到這個點的之前的資訊,和之後的資訊,所以可以想到一個正圖,一個反圖,跑兩遍正圖跑最小值,反圖跑最大值,然後計算兩者的差值,就可以了;
寫的時候又想到一種做法,在跑spfa的時候記錄每一個節點之前的最小值做差,貌似也可以,還更快,不管了,先貼程式碼吧

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
inline int read(){
    int x = 0;int f = 1;char c = getchar();
    while(c<'0'||c>'9'){
        if(c == '-')f = -f;
        c = getchar();
        
    }
    while(c<='9'&&c>='0'){
        x = x*10 + c - '0';
        c = getchar();
    }
    return x*f;
}
queue<int>que;
int q,p,n,m,maxx,lim;
const int maxn = 1000200;
struct edge{
   int from,to,v;
}e[maxn];
struct node{
   int from,to,v;
}ee[maxn];
int heada[maxn],diss[maxn],com[maxn],vall[maxn],val[maxn],vis[maxn],dis[maxn],head[maxn];
void add(int a,int b,int c)
{
   p++;
   e[p].from = head[a];
   e[p].to = b;
   e[p].v = c;
   head[a] = p;
}
void addedge(int a,int b,int c){
    q++;
    ee[q].from = heada[a];
    ee[q].to = b;
    ee[q].v = c;
    heada[a] = q;
}
void spfa(int start){
    for(int i = 1; i<=n; i++)dis[i] = maxn;
    memset(vis,0,sizeof(vis));
    que.push(start);
    vis[start] = 1;
    dis[start] = val[1];
    while(!que.empty()){
        int f = que.front();que.pop();
        vis[f] = 0;
        for(int i = head[f]; i ; i = e[i].from){
            int u = e[i].to;
            if(dis[u] > min(dis[f] , e[i].v)){
                dis[u] = min(dis[f],e[i].v);
                if(!vis[u]){
                    vis[u] = 1;
                    que.push(u);
                }
            }
        }
    }
}

void spfa2(int start){
    for(int i = 1; i<=n; i++)diss[i] = maxn;
    memset(vis,0,sizeof(vis));
    que.push(start);
    vis[start] = 1;
    diss[start] = val[n];
    while(!que.empty()){
        int f = que.front();que.pop();
        vis[f] = 0;
        for(int i = heada[f]; i ; i = ee[i].from){
            int u = ee[i].to;
            if(diss[u] > max(diss[f] , ee[i].v)){
                diss[u] = max(diss[f] , ee[i].v);
                maxx = max(maxx,diss[u] - dis[u]);
                if(!vis[u]){
                    vis[u] = 1;
                    que.push(u);
                }
            }
        }
    }
}

int main(){
    n = read(); m = read();
    for(int i = 1; i<=n; i++){
     vall[i] = val[i] = read(); 
    }
    for(int i = 1; i<=m; i++){
        int a = read(),b = read(),opt = read();
        if(opt == 1){
            add(a,b,val[b]);
            addedge(b,a,val[a]);
        }
        else {
            add(b,a,val[a]);add(a,b,val[b]);
            addedge(b,a,val[a]);addedge(a,b,val[b]);
        }
    }
    com[1] = val[1];
    spfa(1);
   // for(int i = 1; i<=n; i++)cout<<com[i]<<' ';
    diss[n] = val[n];
    spfa2(n);
//  cout<<'\n';
    //for(int i = 1; i<=n; i++)cout<<dis[i]<<' ';
    cout<<maxx;
    return 0;
}
  

再說尋找道路,一開始完全懵,懵了好長時間,時不時的去想這道題,但完全不會啊啊啊!!!最後還是仔細仔細仔細看了題解,
然後,這是啥,我在看啥,這是什麼??? 跑反圖???那不能到的點不還是到不了嗎???還是一臉懵逼,直到有一天我突然開竅了,跑完反圖,不能到的點所連線的點就是不能在路徑裡的點,因為是反圖,所以每一塊不能連向終點的點只有和外部所連線的第一個點會在跑反圖的時候跑到,所以遍歷未能到達點並標記,這就是不能到達的點,,,比較奇妙的做法

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
inline int read(){
  int x = 0;int f = 1; char c = getchar();
  while(c<'0'||c>'9'){
      if(c == '9')f = -f;
      c = getchar();
  }
  while(c<='9'&&c>='0'){
      x = x*10 + c - '0';
      c = getchar();
  }
  return x*f;
}
const int maxn = 200500;
int pp,p,n,m,s,t;
struct edge{
  int from,to,v;
}e[maxn],ee[maxn];
int head[maxn],heada[maxn];
void add(int a,int b,int c){
  p++;
  e[p].from = head[a];
  e[p].to = b;
  e[p].v = c;
  head[a] = p;
}
void addedge(int a,int b,int c){
  pp++;
  ee[pp].from = heada[a];
  ee[pp].to = b;
  ee[pp].v = c;
  heada[a] = p;
}

int dis[maxn],vis[maxn],color[maxn];
queue<int>que;
void spfa(int start){
  for(int i = 1; i<=n; i++){
      dis[i] = maxn;
  }
  memset(vis,0,sizeof(vis));
  dis[start] = 0;
  vis[start] = 1;
  que.push(start);
  while(!que.empty()){
      int f = que.front();que.pop();

      //cout<<f<<' ';
      vis[f] = 0;
      for(int i = head[f] ; i ; i = e[i].from){
          int u =  e[i].to;
          if(dis[u] > dis[f] + e[i].v){
              dis[u] = dis[f] + e[i].v;
              if(!vis[u]){
                  vis[u] = 1;
                  que.push(u);
              }
          }
      }
  
  }   
  return;
}
void spfa2(int start){
  for(int i = 1; i<=n; i++){
      dis[i] = maxn;
  }
  memset(vis,0,sizeof(vis));
  dis[start] = 0;
  vis[start] = 1;
  que.push(start);
  while(!que.empty()){
      int f = que.front();que.pop();
      if(color[f])continue;
      //cout<<f<<' ';
      vis[f] = 0;
      for(int i = heada[f] ; i ; i = ee[i].from){
          int u =  ee[i].to;
          if(dis[u] > dis[f] + ee[i].v){
              dis[u] = dis[f] + ee[i].v;
              if(!vis[u]){
                  vis[u] = 1;
                  que.push(u);
              }
          }
      }
  
  }   
  return;
}

int main(){
  n = read(); m = read();
  for(int i = 1; i<=m; i++){
      int a = read(), b = read();
      add(b,a,1);
      addedge(a,b,1);
  }
  s = read(); t = read();
  spfa(t);//cout<<" wxd ";
//  cout<<dis[s];
  for(int i = 1; i<=n;i ++){
      if(dis[i] == maxn){
          for(int j = head[i]; j; j = e[j].from){
              color[e[j].to] = 1;
          }
      }
  }
  //for(int i = 1; i<=n; i++)cout<<dis[i]<<' ';
  spfa2(s);

  if(dis[t] == maxn)printf("-1");
  else printf("%d",dis[t]);
  
  return 0;
}