1. 程式人生 > >計蒜客 - 電能傳輸(最短路)

計蒜客 - 電能傳輸(最短路)

https://nanti.jisuanke.com/t/10772

  • 5000ms
  • 262144K

題目描述

在嘟嘟生活的王國有 n 座城市,某些城市之間有傳輸電能的線路。在某條線路傳輸電能是會有損耗的,某一個城市在某一時間只可以向另外一個城市傳輸電能。已知在城市 s 存在 m 千瓦時電能,求將這些電能都傳輸到城市 t ,至少需要損耗多少電能。

輸入格式

輸入包含多組測試資料,對於每組測試資料:

第一行包含一個整數 n ( 0 < n ≤ 50000 ) 。

接下來輸入包含 n 部分,對於第 i ( 1 ≤ i ≤ n )部分:第一行包含一個整數 num ( num ≤ 50 ) ,表示城市 i 可以向 num 個城市傳輸電能;接下來 num 行每行包含兩個整數 x y ( 1 ≤ x ≤ n ; x != i ; 0 ≤ y ≤ 100 ) ,表示城市 i 可以向城市 x 傳輸電能,在傳輸時將會損失 y% 的電能。

最後一行包含三個整數 s t m ( 1 ≤ s,t ≤ n ; 1 ≤ m ≤ 1000000 ) 。

輸出格式

對於每組測試資料,如果城市 s 不能向城市 t 傳輸電能,則輸出 "IMPOSSIBLE!" ;否則輸出一個小數,表示損失電能的最小量,結果保留兩位小數。

樣例輸入

5
2
2 20
3 40
2
3 90
4 50
2
2 40
4 90
1
5 80
0
1 5 1000

樣例輸出

920.00

解題思路

這是一道最短路問題,用dis[i]存s到t的最小損失,再用一個數組把傳送到每個地點的電能存下來,以便計算下一個的損失,然後跑一遍最短路就行了。
Dijkstra:

#include <stdio.h>
#include <string.h>
#define N 50000
const double inf = 99999999;
int vis[N + 10], f[N + 10], n, cnt;
double dis[N + 10], arr[N + 10], minn;
struct edge {
    int u, v;
    double w;
}e[N * 50 + 10];
void Add(int u, int v, int w)
{
    e[++cnt] = (edge){f[u], v, w / 100.0};
    f[u] = cnt;
}
void Dijkstra(int s, int m)
{
    int k;
    dis[s] = 0;
    arr[s] = m;
    for (int i = 1; i <= n; i++)
    {
        minn = inf;
        for (int j = 1; j <= n; j++)
            if (!vis[j] && dis[j] < minn)
                minn = dis[k = j];
        vis[k] = 1;
        for (int j = f[k]; j; j = e[j].u)
        {
            int v = e[j].v;
            if (e[j].w < 1 && !vis[v]&&dis[v] > dis[k] + arr[k] * e[j].w)
            {
                dis[v] = dis[k] + arr[k] * e[j].w;
                arr[v] = arr[k] * (1 - e[j].w);
            }
        }
    }
}
int main()
{
    int m, num, x, y, s, t;
    while (~scanf("%d", &n))
    {
        cnt = 0;
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= n; i++)
        {
            vis[i] = 0;
            arr[i] = dis[i] = inf;
            for (int j = f[i]; j; j = e[j].u)
                e[j].w = 1;
        }
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &num);
            while (num--)
            {
                scanf("%d%d", &x, &y);
                Add(i, x, y);
            }
        }
        scanf("%d%d%d", &s, &t, &m);
        Dijkstra(s, m);
        if (dis[t] < inf)
            printf("%.2f\n", dis[t]);
        else printf("IMPOSSIBLE!\n");
    }
    return 0;
}

Dijkstra佇列優化:

#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
#define N 50000
using namespace std;
typedef pair <double, int> PII;
const double inf = 99999999;
int vis[N + 10], f[N + 10], n, cnt;
double dis[N + 10], arr[N + 10], minn;
struct edge {
    int u, v;
    double w;
}e[N * 50 + 10];
void Add(int u, int v, int w)
{
    e[++cnt] = (edge){f[u], v, w / 100.0};
    f[u] = cnt;
}
void Dijkstra(int s, int m)
{
    priority_queue <PII, vector<PII>, greater<PII> > Q;
    dis[s] = 0;
    arr[s] = m;
    Q.push(PII(0, s));
    while (!Q.empty())
    {
        PII u = Q.top();
        Q.pop();
        if (vis[u.second])
            continue;
        vis[u.second] = 1;
        for (int j = f[u.second]; j; j = e[j].u)
        {
            int v = e[j].v;
            if (dis[v] > u.first + arr[u.second] * e[j].w)
            {
                dis[v] = u.first + arr[u.second] * e[j].w;
                arr[v] = arr[u.second] * (1 - e[j].w);
                Q.push(PII(dis[v], v));
            }
        }
    }
}
int main()
{
    int m, num, x, y, s, t;
    while (~scanf("%d", &n))
    {
        cnt = 0;
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= n; i++)
        {
            vis[i] = 0;
            arr[i] = dis[i] = inf;
            for (int j = f[i]; j; j = e[j].u)
                e[j].w = 1;
        }
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &num);
            while (num--)
            {
                scanf("%d%d", &x, &y);
                Add(i, x, y);
            }
        }
        scanf("%d%d%d", &s, &t, &m);
        Dijkstra(s, m);
        if (dis[t] < inf)
            printf("%.2f\n", dis[t]);
        else printf("IMPOSSIBLE!\n");
    }
    return 0;
}

Bellman-Ford: 

#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
#define N 50000
using namespace std;
const double inf = 99999999;
int vis[N + 10], f[N + 10], n, cnt;
double dis[N + 10], arr[N + 10], minn;
struct edge {
    int u, v;
    double w;
}e[N * 50 + 10];
void Add(int u, int v, int w)
{
    e[++cnt] = (edge){f[u], v, w / 100.0};
    f[u] = cnt;
}
void Bellman_Ford(int s, int m)
{
    queue <int> Q;
    Q.push(s);
    dis[s] = 0;
    vis[s] = 1;
    arr[s] = m;
    while (!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        vis[u] = 0;
        for (int j = f[u]; j; j = e[j].u)
        {
            int v = e[j].v;
            if (dis[v] > dis[u] + arr[u] * e[j].w)
            {
                dis[v] = dis[u] + arr[u] * e[j].w;
                arr[v] = arr[u] * (1 - e[j].w);
                if (!vis[v])
                {
                    vis[v] = 1;
                    Q.push(v);
                }
            }
        }
    }
}
int main()
{
    int m, num, x, y, s, t;
    while (~scanf("%d", &n))
    {
        cnt = 0;
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= n; i++)
        {
            vis[i] = 0;
            arr[i] = dis[i] = inf;
            for (int j = f[i]; j; j = e[j].u)
                e[j].w = 1;
        }
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &num);
            while (num--)
            {
                scanf("%d%d", &x, &y);
                Add(i, x, y);
            }
        }
        scanf("%d%d%d", &s, &t, &m);
        Bellman_Ford(s, m);
        if (dis[t] < inf)
            printf("%.2f\n", dis[t]);
        else printf("IMPOSSIBLE!\n");
    }
    return 0;
}