原题链接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; }