图论 ---- E. Minimum Path(分层图最短路 用分层图对边权操作进行选择)

题目链接


题目大意:

两点间最短路的定义变成: 所 有 的 边 之 和 − m a x + m i n 所有的边之和-max+min max+min


解题思路:

这里很明显就是变成了最短路的时时候就是把路径上边权最小值乘2,然后把最大值去掉?
相当于免费?

是不是很像分层图?
就是你有两次机会:1.你可以把一条路径上的边权变成0。2.是把边权翻倍

为什么跑分层图最短路就是答案呢?
因为根据最短路的性质肯定是去大边,翻倍小边

我们一共有4种状态:
1.两个机会都没用
2.用了第一个条件,第二个没用
3.用了第二个条件,第一个没用
4.两个都用了

那么直接4个状态这样是不是就可以了呢?
在这里插入图片描述

肯定是不行的
因为可能两点间的最短路只有一条边??
那么你这个分层图要到4至少要两条边??
那么怎么办?
在这里插入图片描述
第一层和第4层再连一条边


AC code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 200010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
   x = 0;char ch = getchar();ll f = 1;
   while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
   while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
   read(first);
   read(args...);
}
struct node {
   int nxt, to, val;
}edge[maxn*20];
int head[maxn<<2], cnt;
int n, m;
inline void add(int from, int to, int val) {
   edge[cnt] = {head[from],to,val};
   head[from] = cnt ++;
}
priority_queue<PII, vector<PII>, greater<PII> > q;
ll dist[maxn<<2];
bool vis[maxn<<2];
inline void dij() {
   ms(dist,LLF);
   dist[1] = 0;
   q.push({0,1});
   while(!q.empty()) {
      auto top = q.top();
      q.pop();
      if(vis[top.second]) continue;
      vis[top.second] = 1;
      for(int i = head[top.second]; ~i; i = edge[i].nxt) {
         int to = edge[i].to;
         if(dist[to] > dist[top.second] + edge[i].val) {
            dist[to] = dist[top.second] + edge[i].val;
            q.push({dist[to],to});
         }
      }
   }
}

int main() {
    IOS;
    ms(head,-1);
    cin >> n >> m;
    for(int i = 1; i <= m; ++ i) {
       int u, v, w;
       cin >> u >> v >> w;
       for(int j = 0; j <= 3; j ++) add(u+j*n,v+j*n,w),add(v+j*n,u+j*n,w);
       
       add(u,v+3*n,w);
       add(v,u+3*n,w);

       add(u,v+n,2*w);
       add(v,u+n,2*w);

       add(u,v+2*n,0);
       add(v,u+2*n,0);
       
       add(u+n,v+3*n,0);
       add(v+n,u+3*n,0);
       
       add(u+2*n,v+3*n,2*w);
       add(v+2*n,u+3*n,2*w);
    }
    dij();
    for(int i = 2; i <= n; ++ i) cout << dist[i+3*n] << " ";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值