给一个无向图,外加一些特殊的连接原点的无向边。在不改变原点与所有点的最短路的情况下,最多可以删除多少条特殊边?
首先我们把所有的边夹杂在一起。spfa跑出与所有点的最短路。
接下来我们通过一次bfs来判断哪些特殊的边是可以删除的。这里面的原理跟迪杰斯特拉算法差不多。
首先把原点加入队列,所有的特殊边按照长度排序,然后一直沿着非特殊边和最短的路径增广,把满足最短路条件的点都拉到队列里面来,直到队列元素为空,然后判断特殊边的最短的那一条边是否关键边,是的话就把它所连接的那个点拉到队列里面来。程序一直进行直到队列元素空且所有的特殊边都进行过判断为止。
召唤代码君:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 1111111 typedef long long ll; using namespace std; struct EG{ ll v,w; }E[500100]; ll inf=~0U>>2; ll to[maxn],next[maxn],c[maxn],first[maxn],edge; ll U[maxn],V[maxn],W[maxn],d[maxn]; ll Q[maxn],bot,top; bool iq[maxn]; ll n,m,k,tk,ans=0; bool cmp(EG e1,EG e2) { return e1.w<e2.w; } void addedge(ll uu,ll vv,ll ww) { edge++; to[edge]=vv,c[edge]=ww,next[edge]=first[uu],first[uu]=edge; edge++; to[edge]=uu,c[edge]=ww,next[edge]=first[vv],first[vv]=edge; } void _init() { scanf("%I64d%I64d%I64d",&n,&m,&k); for (ll i=1; i<=n; i++) first[i]=-1,d[i]=inf,iq[i]=false; edge=-1; for (ll i=1; i<=m; i++) scanf("%I64d%I64d%I64d",&U[i],&V[i],&W[i]),addedge(U[i],V[i],W[i]); tk=edge; for (ll i=1; i<=k; i++) { scanf("%I64d%I64d",&E[i].v,&E[i].w); addedge(1,E[i].v,E[i].w); } } void SPFA() { Q[bot=top=1]=1,d[1]=0,iq[1]=true; while (bot<=top) { ll cur=Q[bot++]; iq[cur]=false; for (ll i=first[cur]; i!=-1; i=next[i]) if (d[cur]+c[i]<d[to[i]]) { d[to[i]]=d[cur]+c[i]; if (!iq[to[i]]) Q[++top]=to[i],iq[to[i]]=true; } } } void bfs() { ll topeg=0; sort(E+1,E+1+k,cmp); for (ll i=1; i<=n; i++) iq[i]=false; Q[bot=top=1]=1,iq[1]=true; while (bot<=top || topeg<k) { if (bot<=top) { ll cur=Q[bot++]; for (ll i=first[cur]; i!=-1; i=next[i]) if (i<=tk && d[cur]+c[i]==d[to[i]] && !iq[to[i]]) iq[to[i]]=true,Q[++top]=to[i]; } else { topeg++; if (iq[E[topeg].v] || d[E[topeg].v]<E[topeg].w) ans++; else iq[E[topeg].v]=true,Q[++top]=E[topeg].v; } } } int main() { inf*=inf; _init(); SPFA(); bfs(); printf("%I64d ",ans); return 0; }