P2829 大逃离
P2829 大逃离
题意简述:一个n个节点m条边的无向有权图,将d(度数)<k的点删除,求
首先回顾一下我们写次短路的经典Trick:以S,T分别为源点求两次最短路,然后建立一个最短路树(并不用真的去建它,只需要将所有在最短路上的边打上一个标记就好了)
然后遍历每条边
然后这题其实有个偷懒的地方:
注意如果有多条路径都是最短路径,那么他们都不能叫第2短路径
这提示我们甚至不用记录最短路,直接将边集遍历一遍,
对于所有满足
最小化
然后还要注意的是:在本题中可能有u,v,相同但是w不同的边,这样的的“重边”不能对d(度数)产生贡献
所以我们要去重,这里我用了Map<pair
但其实可以将(x,y)压成一个
(其实用vector存图然后unique一下貌似更好)
坏了我成小丑了
算了不管了反正写了也过了
时间复杂度就是正常dijkstra复杂度
Code:
#include<bits/stdc++.h> #define int long long const int N=1e5+5; const int inf=1e17; using namespace std; int n,m,k,e_cnt,res,ans; struct Edge{ int to,nxt,w; }e[N<<1]; int d[N],dis_s[N],dis_t[N],vis[N],head[N]; int X[N<<1],Y[N<<1],W[N<<1]; void add(int x,int y,int w) { e[++e_cnt]=(Edge){y,head[x],w}; head[x]=e_cnt;d[x]++; } void init(int a[],int val) { for(int i=1;i<=n;i++){a[i]=val;} } struct Node{ int id,w; bool operator<(const Node &a)const{ return a.w<w; } }; priority_queue<Node> Q; void dijkstra(int s,int dis[]) { dis[s]=0; Q.push((Node){s,0}); while(!Q.empty()) { int u=Q.top().id;Q.pop(); if(vis[u])continue; vis[u]=1; for(int i=head[u],v;i;i=e[i].nxt) { v=e[i].to; if(d[v]<k)continue; if(dis[v]>dis[u]+e[i].w) { dis[v]=dis[u]+e[i].w; Q.push((Node){v,dis[v]}); } } } } #define mp(x,y) make_pair(x,y) map<pair<int,int>,bool> Map; void work() { cin>>n>>m>>k; init(dis_s,inf); init(dis_t,inf); for(int i=1;i<=m;i++) { scanf("%lld%lld%lld",&X[i],&Y[i],&W[i]); if(X[i]==Y[i])continue; add(X[i],Y[i],W[i]); add(Y[i],X[i],W[i]); X[i+m]=Y[i]; Y[i+m]=X[i]; W[i+m]=W[i]; d[X[i]]-=Map[mp(X[i],Y[i])]; d[Y[i]]-=Map[mp(Y[i],X[i])]; Map[mp(X[i],Y[i])]=Map[mp(Y[i],X[i])]=1; } d[1]=d[n]=inf; dijkstra(1,dis_s); init(vis,0); dijkstra(n,dis_t); ans=inf; if(dis_s[n]==inf) { cout<<-1; return ; } m<<=1; for(int i=1;i<=m;i++) { if(X[i]==Y[i])continue; if(dis_s[X[i]]+W[i]+dis_t[Y[i]]!=dis_s[n]) { ans=min(ans,dis_s[X[i]]+W[i]+dis_t[Y[i]]); } } printf("%lld\n",ans==inf ? -1 : ans); } #undef int int main() { freopen("P2829.in","r",stdin);freopen("P2829.out","w",stdout); work(); return 0; }