题意:n个城市,中间有m条道路(双向),再给出k条铁路,铁路直接从点1到点v,现在要拆掉一些铁路,在保证不影响每个点的最短距离(距离1)不变的情况下,问最多能删除多少条铁路
分析:先求一次最短路,铁路的权值大于该点最短距离的显然可以删去,否则将该条边加入图中,再求最短路,记录每个点的前一个点,然后又枚举铁路,已经删去的就不用处理了,如果铁路权值大于该点最短距离又可以删去,权值相等时,该点的前一个点如果不为1,则这个点可以由其他路到达,这条铁路又可以删去。
由于本题中边比较多,最多可以有8x10^5条,所以用邻接链表会超时,最好用vector来存储边。
Time:296 ms Memory:30968 KB
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <vector> #include <queue> #define lll __int64 using namespace std; #define N 100006 struct Edge { int v; lll w; Edge(int _v,lll _w) { v = _v; w = _w; } Edge(){} }; struct Train { int v; lll w; }T[N]; vector<Edge> G[N]; lll dis[N]; int n,m; int head[N],tot,pre[N]; int cut[N],vis[N]; queue<int> que; void SPFA(int s) { while(!que.empty()) que.pop(); memset(vis,0,sizeof(vis)); vis[s] = 1; que.push(s); for(int i=0;i<=n;i++) dis[i] = 1000000000000000LL; dis[s] = 0; while(!que.empty()) { int u = que.front(); que.pop(); vis[u] = 0; for(int i=0;i<G[u].size();i++) { int v = G[u][i].v; lll w = G[u][i].w; if(dis[v] > dis[u] + w) { dis[v] = dis[u] + w; if(!vis[v]) { vis[v] = 1; que.push(v); } } } } } void SPFA2() { while(!que.empty()) { int u = que.front(); que.pop(); vis[u] = 0; for(int i=0;i<G[u].size();i++) { int v = G[u][i].v; lll w = G[u][i].w; if(dis[v] > dis[u] + w) { dis[v] = dis[u] + w; pre[v] = u; if(!vis[v]) { que.push(v); vis[v] = 1; } } else if(dis[v] == dis[u] + w && pre[v] < u) pre[v] = u; } } } int main() { int i,j,k; int u,v,y; lll w; while(scanf("%d%d%d",&n,&m,&k)!=EOF) { tot = 0; for(i=0;i<=n;i++) G[i].clear(); memset(head,-1,sizeof(head)); memset(cut,0,sizeof(cut)); memset(pre,-1,sizeof(pre)); for(i=0;i<m;i++) { scanf("%d%d%I64d",&u,&v,&w); G[u].push_back(Edge(v,w)); G[v].push_back(Edge(u,w)); } for(i=0;i<k;i++) { scanf("%d%I64d",&y,&w); T[i].v = y; T[i].w = w; } SPFA(1); int cnt = 0; for(i=0;i<k;i++) { int v = T[i].v; lll w = T[i].w; if(dis[v] <= w) { cut[i] = 1; cnt++; } else { G[1].push_back(Edge(v,w)); G[v].push_back(Edge(1,w)); pre[v] = 1; dis[v] = w; que.push(v); vis[v] = 1; } } SPFA2(); for(i=0;i<k;i++) { if(cut[i]) continue; int v = T[i].v; lll w = T[i].w; if((dis[v] == w && pre[v] != 1) || dis[v] < w) cnt++; } printf("%d ",cnt); } return 0; }