最短路 || 分层图最短路

在对可以任选的一部分边或点有限制的时候,可以建分层图

HDU 3499

题意:n个城市有m条价格不同的航线,从s到t,可以选择一条边价格减半,求最小花费

建两层图,每一层图里连边,两层图里连边

#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 200010;
const int maxm = 1500100;
const LL INF = 1000000000100LL;
map<string, int> mp;
int head[maxn], nxt[maxm], tot;
int vis[maxn];
LL dis[maxn];
struct Edge
{
    int t;
    LL d;
    Edge () {}
    Edge(int t, LL d) : t(t), d(d) {};
} l[maxm];
void build(int f, int t, LL d)
{
    l[++tot] = Edge(t, d);
    nxt[tot] = head[f];
    head[f] = tot;
}
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
    mp.clear();
}
struct node
{
    int u;
    LL d;
    node () {}
    node(int u, LL d) : u(u), d(d) {};
    bool operator < (const node &a) const
    {
        return d > a.d;
    }
};
LL dij(int s, int t)
{
    //bool operator < (node a, node b) {return a.d > b.d; }
    priority_queue<node> q;
    for(int i = 0; i < maxn; i++) dis[i] = INF;
    memset(vis, 0, sizeof(vis));
    dis[s] = 0LL;
    q.push(node(s, 0LL));
    while(q.size())
    {
        int u = q.top().u;
        q.pop();
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = head[u]; ~i; i = nxt[i])
        {
            int v = l[i].t;
            if(dis[v] > dis[u] + l[i].d)
            {
                dis[v] = dis[u] + l[i].d;
                q.push(node(v, dis[v]));
            }
        }
    }
    if(dis[t] == INF) return -1;
    return dis[t];
}
int main()
{
    int n, m;
    while(~scanf("%d%d", &n, &m))
    {
        int idx = 0;
        init();
        for(int i = 0; i < m; i++)
        {
            char str1[13], str2[13];
            LL c;
            scanf(" %s %s %lld", str1, str2, &c);
            if(mp.find(str1) == mp.end()) mp[str1] = idx++;
            if(mp.find(str2) == mp.end()) mp[str2] = idx++;
            build(mp[str1], mp[str2], c);
            build(mp[str1]+n, mp[str2]+n, c);
            build(mp[str1], mp[str2]+n, c/2);
        }
        char st[13], ed[13];
        scanf(" %s %s", st, ed);
        printf("%lld\n", dij(mp[st], mp[ed]+n));
    }
    return 0;
}
View Code

DP做法

#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 100010;
const int maxm = 500100;
const LL INF = 1000000000100LL;
map<string, int> mp;
int head[maxn], nxt[maxm], tot;
int vis[maxn];
LL dis[maxn][2];
struct Edge
{
    int t;
    LL d;
    Edge () {}
    Edge(int t, LL d) : t(t), d(d) {};
} l[maxm];
void build(int f, int t, LL d)
{
    l[++tot] = Edge(t, d);
    nxt[tot] = head[f];
    head[f] = tot;
}
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
    mp.clear();
}
struct node
{
    int u;
    LL d;
    node () {}
    node(int u, LL d) : u(u), d(d) {};
    bool operator < (const node &a) const
    {
        return d > a.d;
    }
};
LL dij(int s, int t)
{
    //bool operator < (node a, node b) {return a.d > b.d; }
    priority_queue<node> q;
    for(int i = 0; i < maxn; i++) dis[i][0] = dis[i][1] = INF;
    memset(vis, 0, sizeof(vis));
    dis[s][0] = 0LL;
    dis[s][1] = 0LL;
    q.push(node(s, 0LL));
    while(q.size())
    {
        int u = q.top().u;
        q.pop();
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = head[u]; ~i; i = nxt[i])
        {
            int v = l[i].t;
            if(dis[v][0] > dis[u][0] + l[i].d)
            {
                dis[v][0] = dis[u][0] + l[i].d;
                q.push(node(v, dis[v][0]));
            }
            if(dis[v][1] > dis[u][0] + l[i].d/2 || dis[v][1] > dis[u][1] + l[i].d)
            {
                dis[v][1] = min(dis[u][0] + l[i].d/2, dis[u][1] + l[i].d);
                q.push(node(v, dis[v][1]));
            }
        }
    }
    //printf("%d %d %lld\n",s,t, dis[t][0]);
    if(dis[t][1] == INF || s == t) return -1;
    return min(dis[t][0], dis[t][1]);
}

int main()
{
    int n, m;
    while(~scanf("%d%d", &n, &m))
    {
        int idx = 0;
        init();
        for(int i = 0; i < m; i++)
        {
            char str1[13], str2[13];
            LL c;
            scanf(" %s %s %lld", str1, str2, &c);
            if(mp.find(str1) == mp.end()) mp[str1] = idx++;
            if(mp.find(str2) == mp.end()) mp[str2] = idx++;
            build(mp[str1], mp[str2], c);
        }
        char st[13], ed[13];
        scanf(" %s %s", st, ed);
        printf("%lld\n", dij(mp[st], mp[ed]));
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/pinkglightning/p/9692639.html