送礼物

题目详情

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值