1. 程式人生 > 其它 >The 2021 CCPC Guilin Onsite (Grand Prix of EDG) K. Tax

The 2021 CCPC Guilin Onsite (Grand Prix of EDG) K. Tax

場上隊友想到正解了,但沒機時了,由於我們打星直接不寫這道題了 賽後1A emmm 如果沒打星 過了這題就金了

題意

\(n\)個點和\(m\)條無向邊,點依次從1到n編號。每條邊有一個顏色,如果這是第\(k\)​次經過顏色為\(c\)的邊,那麼需要\(k\times w_c\)的代價。

對於\(k=2,3,4,...,n\),回答從\(1\)\(k\)​經過邊數最少的情況下最小代價是多少。

保證沒有重邊並且1號點可以到達其它所有點。

\(2\le n\le 50,n-1\le m \le \frac{n(n-1)}{2}\)

Sol

資料很小考慮亂搞

不考慮優化的話 直接DFS更新答案 複雜度為\(n!\)(完全圖)

預處理出1號點到其它點的最短路(分層)後限制步數、方向+最優性剪枝

考慮此時的最壞情況:

如果把圖根據從1到該點的距離分層,假設層與層之間邊數拉滿,每層點數為\(x\)時每走一層都有\(x\)​種選擇,共有\((n-1)/x\)​層,複雜度\(O(x^{\frac{n-1}{x}})\)

這玩意非負,直接取對數得\(\frac{n-1}{x}\times\ln(x)\), 再求導得\(-\frac{n-1}{x^2}\ln(x)+\frac{n-1}{x^2}=\frac{n-1}{x^2}(1-\ln(x))\)

\(x=e\)的時候導數為0 取得最大值

由於\(x\)是整數,把2和3分別帶進去得\(2^{\frac{49}{2}}\)能過,\(3^{\frac{49}{3}}\)

能過

由均值不等式知總點數不變的情況下,每層的點數相同的時候複雜度最大

因此最終複雜度O(能過)

但是搜50次肯定寄了

分完層以後按層數跑 不用最優性剪枝了 往下跑就行了 跑到哪個點就更新一下該點的答案

這樣跑滿是上面算出來的複雜度

// Problem: K. Tax
// Contest: Codeforces - The 2021 CCPC Guilin Onsite (Grand Prix of EDG)
// URL: https://codeforces.com/gym/103409/problem/K
// Memory Limit: 512 MB
// Time Limit: 1500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 57, maxm = 10007;
#define ll long long
int n, m, k, tot;
struct edge {
	int v, c, nxt;
}e[maxm];
ll w[maxm], cnt[maxm], ans[maxn];
int d[maxn], head[maxn], eid;
int rd() {
	int s = 0, f = 1; char c = getchar();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') {s = s * 10 + c - '0'; c = getchar();}
	return s * f;
}
void init() {
	memset(head, -1, sizeof(head));
	memset(d, -1, sizeof(d));
	memset(ans, 0x3f, sizeof(ans));
	eid = 0;
}
void insert(int u, int v, int c) {
	e[eid].v = v;
	e[eid].c = c;
	e[eid].nxt = head[u];
	head[u] = eid++;
}
void bfs() {
	queue<int> q;
	q.push(1);
	d[1] = 0;
	while (!q.empty()) {
		int u = q.front(); 
		//printf("u == %d d[u] == %d\n", u, d[u]);
		q.pop();
		for (int i = head[u]; ~i; i = e[i].nxt) {
			int v = e[i].v;
			if (d[v] == -1) {
				d[v] = d[u] + 1;
				q.push(v);
			}
		}
	}
}
void dfs(int u, ll dis) {
	for (int i = head[u]; ~i; i = e[i].nxt) {
		int v = e[i].v;
		if (d[v] == d[u] + 1) {
			cnt[e[i].c]++;
			ans[v] = min(ans[v], dis + w[e[i].c] * cnt[e[i].c]);
			dfs(v, dis + w[e[i].c] * cnt[e[i].c]);
			cnt[e[i].c]--;
		}
	}
}
int main() {
	n = rd();
	m = rd();
	init();
	for (int i = 1; i <= m; i++) {
		w[i] = rd();
	}
	for (int i = 1, u, v, c; i <= m; i++) {
		u = rd(); 
		v = rd();
		c = rd();
		//printf("u == %d v == %d c == %d\n", u, v, c);
		insert(u, v, c);
		insert(v, u, c);
	}
	bfs();
	dfs(1, 0);
	for (int i = 2; i <= n; i++) {
		printf("%lld\n", ans[i]);
	}
	return 0;
}