2021-09-14

Gym 103081D jogging

原题链接https://codeforces.com/gym/103081/problem/D
题目大意:小女孩在一张图上移动多轮,每一轮会从点0出发最后回到点0,每轮移动的路程在[L,U],每轮必须(至少)到达一条新边,求最多进行多少轮。
题解:其实就是求最多可以到达多少条边,因此求点0到其他点的最短路径dis[i],如果dis[i]*2小于U,则连接点i的边都是可以被到达的。
我是用邻接矩阵和优先队列(小根堆)写的dijkstra,时间复杂度mlogn。
代码如下

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;//这玩意默认大根堆(大的先出队)
vector<pair<int,int>> v[100010];
#define x first
#define y second
const int inf=0x3f3f3f3f;
int dis[100010],vis[100010];
map<pair<int,int>,int> ma;//防止重复算边
void dijkstra(int n)
{
    for(int i=1;i<n;i++)
        dis[i]=inf;
    dis[0]=0;
    q.push({0,0});
    pair<int,int> p,p1;
    while(!q.empty())
    {
        p=q.top();
        q.pop();
        if(vis[p.y])
            continue;
        vis[p.y]=1;
        int vn=v[p.y].size();
        for(int i=0;i<vn;i++)
        {
            p1=v[p.y][i];
            if(dis[p1.x]>p.x+p1.y)
            {
                dis[p1.x]=p.x+p1.y;
                //cout<<p1.x<<" "<<dis[p1.x]<<" "<<p.y<<endl;
                q.push({dis[p1.x],p1.x}); //priority_queue没法修改元素,故直接加入更新后的,并用vis防止重复遍历,入队logn,m条边,故mlogn
            }
        }
    }
}

int main()
{
    int n,m,l,u,a,b;
    cin>>n>>m>>l>>u;
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b>>l;
        v[a].push_back({b,l});
        v[b].push_back({a,l});
    }
    dijkstra(n);
    int ans=0;
    pair<int,int> p;
    for(int i=0;i<n;i++)
    {
        if(dis[i]*2>=u)
            continue;
        //cout<<i<<" "<<dis[i]<<endl;
        int vn=v[i].size();
        for(int j=0;j<vn;j++)
        {
            p=v[i][j];
            a=min(i,p.x),b=max(i,p.x);
            if(ma[{a,b}])
                continue;
            ans++;
            ma[{a,b}]=1;
        }
    }
    cout<<ans<<endl;
    return 0;
}
上一篇:logback异常堆栈信息换行合并为一行处理


下一篇:SpringBoot——日志及原理