寻找道路 & 最优贸易

两道题目都很有意思,都不难但需要开动脑筋去仔细想想;

先说最优贸易,只买一次,卖一次,简化一下题目就是在某个点值
与其之前的所有点的最小的差最大是多少,这样就可以看到一个是之前的最小,一个是之后的最大,我们可以考虑如何找到这个点的之前的信息,和之后的信息,所以可以想到一个正图,一个反图,跑两遍正图跑最小值,反图跑最大值,然后计算两者的差值,就可以了;
写的时候又想到一种做法,在跑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;
}

猜你喜欢

转载自www.cnblogs.com/Euplectella/p/9907262.html
今日推荐