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;
}