文章标题 CoderForces 450D : Jzzhu and Cities(最短路---spfa)

来源:互联网 发布:中经网数据库 编辑:程序博客网 时间:2024/06/06 07:08

Jzzhu and Cities

Description
Jzzhu is the president of country A. There are n cities numbered from 1 to n in his country. City 1 is the capital of A. Also there are m roads connecting the cities. One can go from city ui to vi (and vise versa) using the i-th road, the length of this road is xi. Finally, there are k train routes in the country. One can use the i-th train route to go from capital of the country to city si (and vise versa), the length of this route is yi.
Jzzhu doesn’t want to waste the money of the country, so he is going to close some of the train routes. Please tell Jzzhu the maximum number of the train routes which can be closed under the following condition: the length of the shortest path from every city to the capital mustn’t change.
Input
The first line contains three integers n, m, k (2 ≤ n ≤ 105; 1 ≤ m ≤ 3·105; 1 ≤ k ≤ 105).
Each of the next m lines contains three integers ui, vi, xi (1 ≤ ui, vi ≤ n; ui ≠ vi; 1 ≤ xi ≤ 109).
Each of the next k lines contains two integers si and yi (2 ≤ si ≤ n; 1 ≤ yi ≤ 109).
It is guaranteed that there is at least one way from every city to the capital. Note, that there can be multiple roads between two cities. Also, there can be multiple routes going to the same city from the capital.
Output
Output a single integer representing the maximum number of the train routes which can be closed.
Sample Input
Input
5 5 3
1 2 1
2 3 2
1 3 3
3 4 4
1 5 5
3 5
4 5
5 5
Output
2
Input
2 2 3
1 2 2
2 1 3
2 1
2 2
2 3
Output
2
题意:在n个城市中,有m条公路(双向的),k条铁路(单向),铁路从1到点v,现在要节省金钱拆掉一些铁路,在不影响每个点与点1之间的最短路的情况下,问能拆掉的铁路的最大值。
分析:先求一次最短路,然后铁路的权值与对应的点的最短路的权值比较,如果铁路的比较大,说明可以删掉;否则将将该边加入到图中,再计算一次最短路,并记录每个点的前一个点(即前驱),然后枚举铁路,已经删除的铁路就不用考虑了,如果铁路的权值比最短路的权值大,说明该铁路可以删除,如果权值相等,看这个点的前驱,如果不是1,说明可以从其他点到达,这条铁路也可以删除。
代码:

#include<iostream>#include<string>#include<cstdio>#include<cstring>#include<vector>#include<math.h>#include<map>#include<queue> #include<algorithm>using namespace std;const int inf = 0x3f3f3f3f;const long long INF = 0x3f3f3f3f3f3f3f3f;const int maxn = 105000;typedef pair<int,int> pii;int n,m,k;struct edge{//边的结构体    int v;    long long w;    edge(int _v,long long _w){        v=_v;        w=_w;    }    edge(){}};vector <edge> G[maxn];//用向量存储图struct Train{    int s;    long long y;};Train train[maxn];long long dis[maxn];//源点到各个点的最短路int vis[maxn];//标记是否在队列中queue <int> q;int pre[maxn];//每个点的前驱 int had_cut[maxn]; //标记已经被砍掉的铁路void spfa(){    while (!q.empty()) q.pop();//清除队列    memset(vis,0,sizeof (vis));    for (int i=0;i<maxn;i++) dis[i]=INF;//初始化每个点的最短路为无穷大    dis[1]=0;    q.push(1);    vis[1]=1;    while (!q.empty()){        int u=q.front();q.pop();vis[u]=0;        for (int i=0;i<G[u].size();i++){            int v=G[u][i].v;            long long w=G[u][i].w;            if (dis[v]>dis[u]+w){//如果有更短的路,则松弛                dis[v]=dis[u]+w;                if (!vis[v]){//如果没有在队列中则加入队列                    q.push(v);                    vis[v]=1;                }            }        }    }}void spfa2(){    while (!q.empty()){        int u=q.front();q.pop();vis[u]=0;        for (int i=0;i<G[u].size();i++){            int v=G[u][i].v;            long long w=G[u][i].w;            if (dis[v]>dis[u]+w){                dis[v]=dis[u]+w;                pre[v]=u;//记录前驱                if (!vis[v]){                    q.push(v);                    vis[v]=1;                }            }            else if(dis[v]==dis[u]+w&&pre[v]<u){                pre[v]=u;//记录前驱            }        }    }}int main (){    while (scanf ("%d%d%d",&n,&m,&k)!=EOF){        for (int i=0;i<maxn;i++)G[i].clear();//清空向量        memset (pre,-1,sizeof (pre));        memset (had_cut,0,sizeof (had_cut));         int u,v,x;        for(int i=0;i<m;i++){            scanf ("%d%d%lld",&u,&v,&x);            G[u].push_back(edge(v,x));//加边,无向的            G[v].push_back(edge(u,x));        }        for (int i=0;i<k;i++){            scanf ("%d%lld",&train[i].s,&train[i].y);        }        spfa();//第一次求最短路        int cnt=0;        for (int i=0;i<k;i++){            int v=train[i].s;            long long w=train[i].y;            if (dis[v]<=w){//找权值比最短路大的                had_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;                q.push(v);                vis[v]=1;//标记            }        }        spfa2();//第二次最短路        for (int i=0;i<k;i++){            if (had_cut[i])continue;//已经删除的就直接跳过            int v=train[i].s;            long long w=train[i].y;            if ((dis[v]==w&&pre[v]!=1)||(dis[v]<w)){//如果权值大的或者权值相等但其前驱不是1则说明可以删除                cnt++;            }        }        printf ("%d\n",cnt);//输出答案    }    return 0;}
0 0
原创粉丝点击