牛客算法周周练18A - 小K的疑惑(Dijkstra + 01分类)

在这里插入图片描述在这里插入图片描述

题目大意:

给出一个 n 个节点的树,输入n,再输入n - 1条边,每条边输入u v w表示u到v之间有一条权值为w的边,你需要找到三元组(i, j, k)使得dis(i, j) = dis(i, k) = dis(j, k) 。

解题思路:

观察题意,两点的距离是需要 % 2的,所以说距离非0即1,而i j k 是可以重复的,我们分为0 1 两类:即一个点到节点1的距离的奇偶性。拿奇数为例,比如有n个小球,需要放入(i, j, k)这样的三元组,每个小球可以重复使用,所以一共有n3种方案,偶数也是如此,设到起点的距离为奇数的为ans1, 偶数为ans2, 则最终答案就是ans13 + ans23

Code:

#pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <sstream>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#define pm make_pair
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e4 + 50;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
struct node
{
	int to, dir;
	bool operator < (const node &t) const
	{
		return dir > t.dir;
	}
};
vector<node > e[N];
int n, dis[N];
bool vis[N];

void dijkstra(int s)
{
	for (int i = 1; i <= n; i ++)
		dis[i] = (i == s ? 0 : inf);
	memset(vis, false, sizeof vis);
	priority_queue<node > q;
	q.push({s, 0});
	while (!q.empty())
	{
		auto t = q.top();
		q.pop();
		if (vis[t.to])  continue;
		vis[t.to] = true;
		for (int i = 0; i < e[t.to].size(); i ++)
		{
			int k = e[t.to][i].to;
			if (e[t.to][i].dir + t.dir < dis[k])
			{
				dis[k] = e[t.to][i].dir + t.dir;
				q.push({k, dis[k]});
			}
		}
	}
}

int main()
{
	ios::sync_with_stdio(false);
	cin >> n;
	for (int i = 1; i <= n; i ++)
	{
		int u, v, w;
		cin >> u >> v >> w;
		e[u].push_back({v, w});
		e[v].push_back({u, w});
	}
	dijkstra(1);
	ll ans1 = 0, ans2 = 0;
	for (int i = 1; i <= n; i ++)
		dis[i] % 2 ? ans1++ : ans2++;
	ll ans3 = pow(ans1, 3) + pow(ans2, 3);
	cout << ans3 << endl;
	return 0;
}
posted @ 2020-08-11 17:07  Hayasaka  阅读(54)  评论(0编辑  收藏  举报