08/13 D -> codeforces Round #Pi div 2 E. President and Roads 最短路变形

链接:http://codeforces.com/contest/567/problem/E
题意:
总统只走最短路,给了一个有向图,对于每条边判断是否一定走这条路,如果一定输出 yes如果不一定,那么是否可以减少这个边的权值使得总统一定走这条路,如果可以输出最少减少多少 can ** ,如果不行 输出no。
分析:
对于每个图可能有不只一条的最短路,要找出每条边是否一定要走,如果这条边是在其中一条最短路上,又要判断是否可以通过减少权值来使得他一定要走。
判断一条边是否是最短路中的:
可以先找出经过这条边的从s到t的最短路,判断这个最短路是否等于最终得出的s到t的最短路。如果相等的话,就表示一定要走。
dis表示最终s->t的最短路。
找出经过这条权值为w的边 <u,v> 的最短路,可以在正向建图后再反向建图,先找到正向图中起点为s终点为u的最短路dis1,在反向图 中找到起点为t终点为v的最短路dis2,判断一下dis1+dis2+w == dis 是否成立。如果成立表示这条边就是最短路中的。
但是如果一条边是最短路中的,还需要判断这条边是否是一定要走的边,因为途中可能有多个最短路,这个边可能只是在某一条最短路上,不一定所有最短路都一定要经过这个边。
判断这条边是否是一定要经过的:
这个满足的先前条件是这个边在最短路中。如果一定要经过这条边,可以知道从s->t的最短路的条数,一定等于保证经过这条边的情况下,s->t的最短路的条数。保证经过这条边的情况下的条数,也可用正向图s->u的条数*反向图中t->v的条数。然而要找出这个最短路的条数可以在dijsktra中顺带计算,每次从优先队列中出来的都是最短距离已经确定的点u,在通过这个点来更新与他连通的点v,如果v的之前的最短距离比u的最短路加上权值来的大,说明要更新并且起点到这个点的最短路条数目前只有起点到u点所存在的最短路的条数,如果之前的最短距离跟通过这条边的一样,不需要更新距离但是要将条数增加起点到u点做存在的最短路的条数。
最后判断是否从s->t的最短路的条数等于保证经过这条边的情况下,s->t的最短路的条数,这样就可以了。
不经过求出能否减少权值:
求出经过这条边的最短路与实际的最短路差多少就表示了如果这条边是最短路的话理论权值应该是多少,要将现在的权值减小到应该有的权值-1处。才能变成唯一经过的最短路。如果理论权值是1的话不能减少,因为权值1不能减到0,大于1的话直接输出这条边的权值-(理论权值-1)。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define M 100009
#define mod 119999827
#define INF 1e18
typedef long long ll;
typedef struct
{
    ll to,cost;
    ll from;
}edge;
vector <edge> g[2][M];
ll dis[2][M]; //0正向 1 反向
ll num[2][M];
edge mp[M];
ll s,t;
ll n,m;
typedef pair<ll,ll> P;
void dijkstra(int st,int a)
{
    priority_queue<P , vector<P> , greater<P> > q;
    dis[a][st] = 0;
    num[a][st] = 1;
    q.push(P(0,st));
    while(!q.empty())
    {
        P p = q.top();
        q.pop();
        int v = p.second;
        if(dis[a][v] < p.first) continue;
        for(int i = 0 ;i < g[a][v].size();i++)
        {
            edge e = g[a][v][i];
            if(dis[a][e.to] > dis[a][v] + e.cost)
            {
                dis[a][e.to] = dis[a][v] + e.cost;
                q.push(P(dis[a][e.to],e.to));
                num[a][e.to] = num[a][v]%mod;
            }
            else if(dis[a][e.to] == dis[a][v] + e.cost)
            {
                num[a][e.to] += num[a][v]%mod;
                num[a][e.to] %= mod;
            }
        }
    }
}
int main()
{
    while(scanf("%I64d %I64d %I64d %I64d",&n,&m,&s,&t)==4)
    {
        for(int i = 0;i < 2;i++)
        {
            fill(dis[i],dis[i]+n+1,INF);
            fill(num[i],num[i]+n+1,0);
            for(int j = 0;j <= n;j++)
                g[i][j].clear();
        }
        for(int i = 0;i < m;i++)
        {
            ll a,b,c;
            scanf("%I64d %I64d %I64d",&a,&b,&c);
            mp[i].from = a;
            mp[i].to = b;
            mp[i].cost = c;
            edge e = {b,c};
            g[0][a].push_back(e);
            e = {a,c};
            g[1][b].push_back(e);
        }
        dijkstra(s,0);
        dijkstra(t,1);
        for(int i = 0;i < m;i++)
        {
            edge e = mp[i];
            if(dis[0][e.from] + dis[1][e.to] + e.cost == dis[0][t] && (num[0][e.from]%mod)*(num[1][e.to]%mod)%mod == num[0][t]%mod)  //是最短路中的,并且一定要经过
                printf("YES\n");
            else
            {
                ll a = dis[0][t] - (dis[0][e.from] + dis[1][e.to]);  //
                if(a - 1 > 0)
                printf("CAN %I64d\n",e.cost-a+1);
                else printf("NO\n");
            }
        }
    }
    return 0;
}

你可能感兴趣的:(08/13 D -> codeforces Round #Pi div 2 E. President and Roads 最短路变形)