【BZOJ4774】修路

【题目链接】

【思路要点】

  • 补档博客,无题解。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define MAXQ	1000005
#define MAXN	10005
#define CURR	256
#define INF	1e9
struct edge {int dest, len; };
vector <edge> a[MAXN];
int n, m, d, num[MAXN];
int ans[MAXN][CURR], opt[CURR];
bool inq[MAXN][CURR];
int func(int x) {
	return x + (x << d);
}
int main() {
	ios::sync_with_stdio(false);
	cin >> n >> m >> d;
	for (int i = 1; i <= m; i++) {
		int x, y, z;
		cin >> x >> y >> z;
		a[x].push_back((edge) {y, z});
		a[y].push_back((edge) {x, z});
	}
	int tot = 0;
	for (int i = 1; i <= d; i++)
		num[i] = ++tot;
	for (int i = 1; i <= d; i++)
		num[n - i + 1] = ++tot;
	for (int i = 1; i <= n; i++)
	for (int j = 1; j < 1 << 2 * d; j++)
		if (num[i] && j == 1 << num[i] - 1) ans[i][j] = 0;
		else ans[i][j] = INF;
	for (int curr = 1; curr < 1 << 2 * d; curr++) {
		static int qx[MAXQ], qy[MAXQ];
		int l = 0, r = -1;
		for (int i = 1; i <= n; i++) {
			for (int j = (curr - 1) & curr; j; j = (j - 1) & curr)
				ans[i][curr] = min(ans[i][curr], ans[i][j] + ans[i][curr ^ j]);
			if (ans[i][curr] < INF) {
				inq[i][curr] = true;
				qx[++r] = i;
				qy[r] = curr;
			}
		}
		while (l <= r) {
			int tx = qx[l], ty = qy[l++];
			inq[tx][ty] = false;
			for (unsigned i = 0; i < a[tx].size(); i++)
				if (ans[tx][ty] + a[tx][i].len < ans[a[tx][i].dest][ty]) {
					ans[a[tx][i].dest][ty] = ans[tx][ty] + a[tx][i].len;
					if (!inq[a[tx][i].dest][ty]) {
						qx[++r] = a[tx][i].dest;
						qy[r] = ty;
						inq[qx[r]][qy[r]] = true;
					}
				}
		}
	}
	for (int j = 0; j < 1 << d; j++) {
		int tmp = func(j), tans = INF;
		for (int i = 1; i <= n; i++)
			tans = min(tans, ans[i][tmp]);
		opt[j] = tans;
	}
	for (int i = 1; i < 1 << d; i++)
	for (int j = (i - 1) & i; j; j = (j - 1) & i)
		opt[i] = min(opt[i], opt[j] + opt[i ^ j]);
	if (opt[(1 << d) - 1] == INF) cout << -1 << endl;
	else cout << opt[(1 << d) - 1] << endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值