2024.4.1 学习日志

愚人节快乐!

下午,进行了一个课的上。

图论选讲。

然后写了两题。

T1.飞行路线(分层图板题)

题目说可以有k次机会不花钱。

那么我们就可以分层图,跑djikstra。(具体建图看代码注释)

code:

#include<bits/stdc++.h>
//#define int long long
#define debug puts("hwl");
using namespace std;
const int N = 1e5 + 10, M = 2e6 + 10;
vector<pair<int, int> > v[M];

bool vis[M];
int dis[M];
void dijkstra(int s){
    memset(dis, 0x3f, sizeof dis);
    priority_queue<pair<int, int> > q;
    q.push({0, s});
    dis[s] = 0;
    while(!q.empty()){
        auto e1 = q.top();
        q.pop();
        int x = e1.second;
        if(vis[x]) continue;
        vis[x] = 1;
        for(auto e : v[x]){
            int y = e.first, w = e.second;
            if(vis[y]) continue;
            if(dis[y] > dis[x] + w){
                dis[y] = dis[x] + w;
                q.push({-dis[y], y});
            }
        }
    }
    return;
}

int main() {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n, m, k, s, t;
    cin >> n >> m >> k >> s >> t;
    for(int i = 1; i <= m; i++){
        int x, y, w;
        cin >> x >> y >> w;
        v[x].push_back({y, w});
        v[y].push_back({x, w});
        for(int j = 1; j <= k; j++){
            v[x + (j - 1) * n].push_back({y + j * n, 0});
            v[y + (j - 1) * n].push_back({x + j * n, 0});
            v[x + j * n].push_back({y + j * n, w});
            v[y + j * n].push_back({x + j * n, w});
        }//这里为什么这样建边  我的理解
        /*
        首先x和y之间有一条边权为w的边。
        我们可以选择分层图。
        每次层数低的只能向刚好比它层数高一的连边。
        低的x向高的y连一条边权为0的边,同时低的y向高的x连一条边权为0的边。
        同一层的x,y连长度为w的边。
        到最高的那一层就表示我们“免费”次数用完了。
        */
    }
    dijkstra(s);
    int ans = 0x3f3f3f3f;
    for(int i = 0; i <= k; i++)
        ans = min(ans, dis[t + i * n]);
    cout << ans << endl;
    return 0;
}//by hwl

T2.The Captain

可以飞快地想到O(n^2)的做法。

但是这会TLE,那怎么办?

可以发现我们建的那么多边很多都是无用的。

我们发现假设(x1,y1)和(x2,y2)之间(之间可以理解为它们形成的长方形中的某一点)有一点。

那么我们从中间这样间接过来一定比直接过去要优。(可以画画图手玩一下)

所以只需要分别按x,y排序。

然后分别将相邻的点连边,跑dijkstra即可。

#include<bits/stdc++.h>
#define int long long
#define debug puts("hwl");
using namespace std;
const int N = 2e5 + 10;

struct Date{
    int x, y, idx;
}p[N];
vector<pair<int, int>> v[N];

bool cmp1(Date a, Date b){
    return a.x < b.x;
}

bool cmp2(Date a, Date b){
    return a.y < b.y;
}

bool vis[N];
int dis[N];
void dijkstra(int s){
    memset(dis, 0x3f, sizeof dis);
    dis[s] = 0;
    priority_queue<pair<int, int>> q;
    q.push({0, s});
    while(!q.empty()){
        auto now = q.top();
        q.pop();
        int x = now.second;
        if(vis[x]) continue;
        vis[x] = 1;
        for(auto e : v[x]){
            int y = e.first, w = e.second;
            if(vis[y]) continue;
            if(dis[y] > dis[x] + w){
                dis[y] = dis[x] + w;
                q.push({-dis[y], y});
            }
        }
    }
    return;
}

signed main() {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++){
        int x, y;
        cin >> x >> y;
        p[i] = Date{x, y, i};
    }
    sort(p + 1, p + 1 + n, cmp1);
    for(int i = 1; i < n; i++){
        int j = i + 1;
        int x1 = p[i].x ,y1 = p[i].y, x2 = p[j].x, y2 = p[j].y;
        v[p[i].idx].push_back({p[j].idx, min(abs(x1 - x2), abs(y1 - y2))});
        v[p[j].idx].push_back({p[i].idx, min(abs(x1 - x2), abs(y1 - y2))});
    }
    sort(p + 1, p + 1 + n, cmp2);
    for(int i = 1; i < n; i++){
        int j = i + 1;
        int x1 = p[i].x ,y1 = p[i].y, x2 = p[j].x, y2 = p[j].y;
        v[p[i].idx].push_back({p[j].idx, min(abs(x1 - x2), abs(y1 - y2))});
        v[p[j].idx].push_back({p[i].idx, min(abs(x1 - x2), abs(y1 - y2))});
    }
    dijkstra(1);
    cout << dis[n] << endl;
    return 0;
}//by hwl

晚上,正在进行中。。。

  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值