a180285 非常喜欢滑雪。他来到一座雪山,这里分布着 m 条供滑行的轨道和 n 个轨道之间的交点(同时也是景点),而且每个景点都有一编号 i (1≤i≤n) 和一高度 h。
a180285 能从景点 i 滑到景点 j 当且仅当存在一条 i 和 j 之间的边,且 i 的高度不小于 j。与其他滑雪爱好者不同,a180285 喜欢用最短的滑行路径去访问尽量多的景点。如果仅仅访问一条路径上的景点,他会觉得数量太少。
于是 a180285 拿出了他随身携带的时间胶囊。这是一种很神奇的药物,吃下之后可以立即回到上个经过的景点(不用移动也不被认为是 a180285 滑行的距离)。
请注意,这种神奇的药物是可以连续食用的,即能够回到较长时间之前到过的景点(比如上上个经过的景点和上上上个经过的景点)。 现在,a180285站在 1 号景点望着山下的目标,心潮澎湃。他十分想知道在不考虑时间胶囊消耗的情况下,以最短滑行距离滑到尽量多的景点的方案(即满足经过景点数最大的前提下使得滑行总距离最小)。你能帮他求出最短距离和景点数吗?
输入的第一行是两个整数 n,m。 接下来一行有 n 个整数 h
i
,分别表示每个景点的高度。
接下来 m 行,表示各个景点之间轨道分布的情况。每行三个整数 u,v,k 表示编号为 uu的景点和编号为 v 的景点之间有一条长度为 k 的轨道。
输出一行,表示 a180285 最多能到达多少个景点,以及此时最短的滑行距离总和。
3 3
3 2 1
1 2 1
2 3 1
1 3 10
3 2
首先拿道题,觉得十分简单,随手写了一个近似模板的Kruskal的代码,嗯~~不错,WA 0了,于是开始仔细读题,
以最短滑行距离滑到尽量多的景点的方案。居然还要遍历的点最多,有点麻烦啊。于是,开始瞎搞。
当两个顶点有边相连,找到高度大的顶点作为起点,高度小的顶点作为终点,边的长度作为距离,放进一个数组。
要使遍历的点最多,即得到从一开始包含最多点的图,可以写一个bfs,先将起点1压入队,然后把起点能直接到达的点继续压入,并将计数器加一下。直到已经不能找到其他可以达到的点。可以用一个结构体存储起点、终点、距离,并用一个二维vector存储结构体以便找到与之相连的点。设置一个结构体数组,当找到可以扩展的顶点时,将当时vector中的起点,终点,距离全部赋给数组,可以更好地进行下面的Kruskal。
综上所述,可以写出代码:
void bfs() {
vis[1] = 1;
jis[++numr] = 1;
while(numl < numr) {
ll f = jis[++numl];
int Size = vec[f].size();
for(int i = 0;i < Size;i ++) {
a[++cnt].u = f;
a[cnt].v = vec[f][i].v;
a[cnt].w = vec[f][i].w;
if(!vis[a[cnt].v]) {
vis[a[cnt].v] = 1;
tmp ++;
jis[++numr] = a[cnt].v;
}
}
}
}
由于先要满足遍历的点最多,所以说当前边终点要从从大到小排序,这样可以满足高度不上升,也就可以满足能到达最多的点。在此情况下,高度已经不下降了,如果有两条边,终点高度相等,就需要距离尽量小,以满足距离在最多点的情况下最小这一条件。
代码:
friend bool operator<(node x, node y) {
return (high[x.v] == high[y.v]) ? x.w < y.w : high[x.v] > high[y.v];
}
emm…没什么别的,把模板贴上去就行了。
其他的几乎就没什么难的了,不过码量有点大,近2k,我调了一个晚自习(约3 hour).
终于又写(水)了一片题解,愉快的代码时间:
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const ll MAX_NODE = 2e6 + 5;
const ll MAX_EDGE = 2e6 + 5;
ll n, m, high[MAX_NODE], cnt, numl, numr, jis[MAX_EDGE];
ll judge, fa[MAX_NODE], ans, tmp, head[MAX_EDGE];
bool vis[MAX_EDGE];
struct node {
ll u, v, w;
node() {}
node(ll U, ll V, ll W) { u = U, v = V, w = W; }
friend bool operator<(node x, node y) {
return (high[x.v] == high[y.v]) ? x.w < y.w : high[x.v] > high[y.v];
}
} a[MAX_EDGE];
struct data {
long long v, w;
data() {}
data(int V, int W) { v = V, w = W; }
} b[MAX_EDGE];
vector<data> vec[MAX_EDGE];
ll Find_Set(ll x) {
if (fa[x] == x)
return x;
return fa[x] = Find_Set(fa[x]);
}
void add(ll u, ll v, ll c) { vec[u].push_back(data(v, c)); }
void bfs() {
vis[1] = 1;
jis[++numr] = 1;
while (numl < numr) {
ll f = jis[++numl];
int Size = vec[f].size();
for (int i = 0; i < Size; i++) {
a[++cnt].u = f;
a[cnt].v = vec[f][i].v;
a[cnt].w = vec[f][i].w;
if (!vis[a[cnt].v]) {
vis[a[cnt].v] = 1;
tmp++;
jis[++numr] = a[cnt].v;
}
}
}
}
int main() {
scanf("%lld %lld", &n, &m);
for (ll i = 1; i <= n; i++) scanf("%lld", &high[i]);
for (ll i = 1; i <= m; i++) {
ll x, y, z;
scanf("%lld %lld %lld", &x, &y, &z);
if (high[x] <= high[y])
add(y, x, z);
if (high[y] <= high[x])
add(x, y, z);
}
bfs();
sort(a + 1, a + cnt + 1);
for (ll i = 1; i <= n; i++) fa[i] = i;
for (ll i = 1; i <= cnt; i++) {
ll x = Find_Set(a[i].u);
ll y = Find_Set(a[i].v);
if (x == y)
continue;
fa[x] = y;
ans += a[i].w;
}
printf("%lld %lld", tmp + 1, ans);
return 0;
}
END