Codeforces 449B Jzzhu and Cities(最短路)

题目传送门:http://codeforces.com/contest/450/problem/D

题意:一个城市,有m条道路,还有k条铁路(铁路都与点1相连),问在不改变点1到各个点的最短路的前提下最多可以删除多少条铁路

思路:将道路和铁路一起建在同一个图中,跑一遍最短路并记录每个点的入度,接下来有两种情况可以判断可以删除这条铁路。

1,如果最短路比铁路到点1的距离短,那毫无疑问可以删除

2,如果最短路和铁路到点1的距离相同,那么如果入度大于1的话,说明可以通过走别的点到达,不需要铁路所以也可以删除


总结:

这道题一开始我是先用道路建的边,然后跑一边dijkstra,然后用铁路的长度和仅以道路构成的最短路去比较,判断是不是可以不用这条铁路。这样做,疯狂wa在第五个测试点,是因为忽略了某条铁路引来的某点最短路改变,会导致其他点的最短路可能也会随之而变,这样就不能仅仅用刚才道路跑出来的dijkstra来判断了。很伤......


AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
const int maxm = 800005;
const ll INF = 1e16;
struct Edge
{
    int v, nxt;
    ll w;
}edges[maxm];
struct HeapNode
{
    int u;
    ll d;
    HeapNode(){}
    HeapNode(int from, ll _distance):u(from), d(_distance){}
    bool operator < (const HeapNode &other)const
    {
        return d > other.d;
    }
};
bool vis[maxn];
struct Dijkstra
{
    int n, head[maxn], eid;
    ll dis[maxn], in[maxn];
    void init(int n)
    {
        this->n = n;
        eid = 0;
        memset(head, -1, sizeof(head));
        memset(in, 0, sizeof(in));
    }
    void AddEdge(int from, int to, ll w)
    {
        edges[eid].v = to;
        edges[eid].w = w;
        edges[eid].nxt = head[from];
        head[from] = eid++;
    }
    void dijkstra(int s)
    {
        for(int i = 0; i <= n; i++)
            dis[i] = INF;
        priority_queue<HeapNode> q;
        dis[s] = 0;
        q.push(HeapNode(s, dis[s]));
        while(!q.empty())
        {
            HeapNode now = q.top();
            q.pop();
            if(vis[now.u])
                continue;
            vis[now.u] = true;
            int u = now.u;
            for(int i = head[u]; i != -1; i = edges[i].nxt)
            {
                int v = edges[i].v;
                if(dis[v] == dis[u] + edges[i].w)
                    in[v]++;
                if(dis[v] > dis[u] + edges[i].w)
                {
                    dis[v] = dis[u] + edges[i].w;
                    in[v] = 1;
                    q.push(HeapNode(v, dis[v]));
                }
            }
        }
    }
};
struct Train
{
    int v;
    ll dist;
}train[maxn];
int main()
{
    int n, m, k;
    while(cin >> n >> m >> k)
    {
        memset(vis, false, sizeof(vis));
        Dijkstra dij;
        dij.init(n);
        for(int i = 0; i < m; i++)
        {
            int u, v;ll w;
            scanf("%d%d%I64d", &u, &v, &w);
            dij.AddEdge(u, v, w);
            dij.AddEdge(v, u, w);
        }
        for(int i = 0; i < k; i++)
        {
            int v;ll w;
            scanf("%d%I64d", &v, &w);
            train[i].v = v;
            train[i].dist = w;
            dij.AddEdge(1, v, w);
        }
        dij.dijkstra(1);
        ll ans = 0;
        for(int i = 0; i < k; i++)
        {
            if(train[i].dist == dij.dis[train[i].v])
                if(dij.in[train[i].v] > 1)
                {
                    ans++;
                    dij.in[train[i].v]--;
                }
            if(train[i].dist > dij.dis[train[i].v])
                ans++;
        }
        printf("%I64d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值