题目详情
HeHe和XiXi在一个地方玩游戏,XiXi把N-1件礼物(HeHe以前送给XiXi的)分别藏在了另外N-1个地方,这些地方都能互相到达,且所有的边都是有方向的。
现在HeHe要做的事就是去那些地方找回那N-1件礼物给XiXi;
由于每一件礼物都有特殊的意义,所以XiXi要求HeHe每找到一件礼物,就必须马上返回XiXi所在的位置,对她说一句当年送她这件礼物的时候所说的话。
由于每走一个单位长度HeHe需要花费1分钟,XiXi还要求HeHe在最快的时间内把这些礼物带回来交给她,你能帮助HeHe么?
输入
测试数据有T组,每组测试数据开始为两个整数N和M,1 <= N,M <= 100000。
N代表所有的位置,M代表这些位置之间的长度
然后是M行,每行有三个数,u,v,w,即位置u和位置v之间有一条单向的边,距离为w;
你可以假设位置的编号是从1到N,XiXi的位置始终都在1;
输出
对于每组测试数据, 用一行输出HeHe所花费的最短时间。
提醒:问题一定有解。w的范围是100以内的整数。第一个T表示有多少组数据,比如T为2,就表示有两组输入数据。
答题说明
输入样例
1
3 3
1 2 4
2 3 5
3 1 6
输出样例
30
做完了回过头看,这个题与很久之前做过的最短路很像,其实是一样的,不过我不长记性,依旧折腾了一天才总算通过了。都快放弃了,不忍,看了看自己以前的代码,发现一个低调的BUG,顿时觉得自己脑洞大开。。。希望这是被堆排序绊倒的最后一次。
#include<iostream>
#include<fstream>
#include<vector>
using namespace std;
#define INF 0x7fffffff
#define N 100010
typedef struct Node//存储边
{
int val;//边长
int to;//终点
}Node;
Node to[N];
int heap[N];//指针式堆排序...
int top;//堆边界
int get(int hp)//根据堆下标取值
{
return to[heap[hp]].val;
}
void swap(int hp1, int hp2)//交换堆元素,以及数据关联
{
int t = heap[hp1];
heap[hp1] = heap[hp2];
heap[hp2] = t;
to[heap[hp1]].to = hp1;
to[heap[hp2]].to = hp2;
}
void up(int hp)
{
while(hp / 2 > 0 && get(hp) < get(hp / 2))
{
swap(hp / 2, hp);
hp /= 2;
}
}
void make(int n)//如果up函数不坚持到顶,则make如下,否则可从n到n / 2(所有根节点都up过了,堆建立)
{
top = n;
for(int i = 2; i <= n; i++)
{
up(i);
}
}
void down(void)
{
int root = 1;
while(2 * root <= top)
{
int next = 2 * root;//经典模式
if(next + 1 <= top && get(next) > get(next + 1))
{
next++;
}
if(get(root) <= get(next))
{
break;
}
swap(root, next);
root = next;
}
}
vector<Node> rel[N];
vector<Node> relBack[N];
int main(void)
{
int t, n, m;
//ifstream cin("in.txt");
cin >> t;
while(t-- > 0)
{
unsigned long long sum = 0;
int i, k, len;
cin >> n >> m;
for(i = 0; i < N; i++)
{
rel[i].clear();
relBack[i].clear();
}
for(int i = 0; i < m; i++)
{
int a, b;
Node x;
cin >> a >> b >> x.val;
x.to = b;
rel[a].push_back(x);
x.to = a;
relBack[b].push_back(x);
}
for(i = 2; i <= n; i++)
{
to[i].val = INF;
to[i].to = i - 1;//堆与to有一位的错位
heap[i - 1] = i;
}
len = rel[1].size();
for(i = 0; i < len; i++)//直接邻居
{
to[rel[1][i].to].val = rel[1][i].val;
}
make(n - 1);
while(top > 0)//堆中还有元素
{
swap(1, top--);
down();
int place = heap[top + 1];
sum += to[place].val;
int len = rel[place].size();
for(i = 0; i < len; i++)
{
int dis = rel[place][i].to;
int neo = rel[place][i].val + to[place].val;
if(neo < to[dis].val)
{
to[dis].val = neo;
up(to[dis].to);
}
}
}
//反向最短路
for(i = 2; i <= n; i++)
{
to[i].val = INF;
to[i].to = i - 1;
heap[i - 1] = i;
}
len = relBack[1].size();
for(i = 0; i < len; i++)
{
to[relBack[1][i].to].val = relBack[1][i].val;
}
make(n - 1);
while(top > 0)
{
swap(1, top--);
down();
int place = heap[top + 1];
sum += to[place].val;
int len = relBack[place].size();
for(i = 0; i < len; i++)
{
int dis = relBack[place][i].to;
int neo = relBack[place][i].val + to[place].val;
if(neo < to[dis].val)
{
to[dis].val = neo;
up(to[dis].to);
}
}
}
cout << sum << endl;
}
return 0;
}