noip模拟赛 dwarf tower

【问题描述】
Vasya在玩一个叫做"Dwarf Tower"的游戏,这个游戏中有n个不同的物品,
它们的编号为1到n。现在Vasya想得到编号为1的物品。
获得一个物品有两种方式:
1. 直接购买该物品,第i件物品花费的钱为ci
2. 用两件其他物品合成所需的物品,一共有m种合成方式。
请帮助Vasya用最少的钱获得编号为1的物品。
【输入格式】
第一行有两个整数n,m(1<=n<=10000,0<=m<=100000),分别表示有n种物品以
及m种合成方式。
接下来一行有n个整数,第i个整数ci表示第i个物品的购买价格,其中
0<=ci<=10^9。
接下来m行,每行3个整数ai,xi,yi,表示用物品xi和yi可以合成物品ai,其
中(1<=ai,xi,yi<=n; ai<>xi, xi<>yi, yi<>ai)
【输出格式】
一行,一个整数表示获取物品 1 的最少花费。

输入样例: 输出样例:
5 3
5 0 1 2 5
5 2 3
4 2 3
1 4 5
2


【数据规模与约定】
60%的数据, n<=100
100%的数据, n<=10000, m<=100000

分析:稍微想一想就能发现这是最短路,合成操作看成松弛操作就可以了.

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int inf = 0x7fffffff;
int n, m, c[10010], d[10010],head[10010], to[200010], nextt[200010], w[200010], tot = 1;
bool vis[10010];

void add(int x, int y, int z)
{
    w[tot] = z;
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void spfa()
{
    queue <int> q;
    for (int i = 1; i <= n; i++)
    {
        d[i] = c[i];
        vis[i] = 1;
        q.push(i);
    }
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u]; i; i = nextt[i])
        {
            int v = to[i];
            if (d[v] > d[u] + d[w[i]])
            {
                d[v] = d[u] + d[w[i]];
                if (!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &c[i]);
    for (int i = 1; i <= m; i++)
    {
        int t, x, y;
        scanf("%d%d%d", &t, &x, &y);
        add(x, t, y);
        add(y, t, x);
    }
    spfa();
    printf("%d
", d[1]);

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/7748067.html