首页 > 其他分享 >Atcoder ABC308H Make Q

Atcoder ABC308H Make Q

时间:2023-07-10 20:12:59浏览次数:41  
标签:Atcoder ABC308H val int Make https 短路 dis

考虑枚举唯一一个度数为 \(3\) 的点 \(u\),即既在环上又与非环上一点相连的那个点。

接下来考虑先处理环,那可以先把 \(u\) 从图上删掉,环的最短距离便是与 \(u\) 有连边的 \(2\) 个点在图上最短路长度加上 \(2\) 个点与 \(u\) 连边的长度,即 \(\min\{w_{u, i} + w_{u, j} + \operatorname{dis}(i, j)\}((u, i), (u, j)\in E)\)(\(w_{u, v}\) 代表 \((u, v)\) 这条边的长度,\(\operatorname{dis}(u, v)\) 代表 \((u, v)\) 在图中的最短路)。
但是发现 \(i, j\) 不能枚举直接跑最短路也不妥,考虑怎么处理。
因为 \(i, j\) 不同所以 \(i, j\) 二进制肯定至少 \(1\) 位不同,那就可以枚举二进制位 \(x\) 了,把编号二进制第 \(x\) 位为 \(1\) 的点当作起点,编号二进制第 \(x\) 位为 \(0\) 的点当作终点跑,这样能保证每个环都能跑到。
然后就可以处理单独的那一条边了,找到这个环与 \(u\) 相连的点 \(i, j\),这部分答案即为 \(\min\{w_{u, k}\}(k\not ={i}, k\not ={j}, (u, k)\in E)\)。

但是注意可能会有更优的解:
\((u, x)\) 或 \((u, y)\) 为单独的边,剩下部分再跑出一个环两部分总和。
所以再删除 \(x\) 或删除 \(y\) 然后同样方法跑图上的最短环加上这条边的长度即可。

使用朴素 \(\text{Dijkstra}\) 跑最短路,时间复杂度 \(O(n^3\log_2 n)\)。

// lhzawa(https://www.cnblogs.com/lhzawa/)
// Problem: Ex - Make Q
// Contest: AtCoder - AtCoder Beginner Contest 308
// URL: https://atcoder.jp/contests/abc308/tasks/abc308_h
// Memory Limit: 1024 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
const int N = 3e2 + 10;
const int inf = 0x3f3f3f3f;
int w[N][N], p[N][N];
int hd[N], ltot;
int n;
int z[N], dis[N], vis[N], lst[N];
int dij(int u, int &x, int &y) {
	for (int i = 1; i <= n; i++) {
		dis[i] = inf, vis[i] = 0, lst[i] = 0;
	}
	for (int i = 1; i <= n; i++) {
		if (z[i] && w[u][i] < inf) {
			dis[i] = w[u][i];
		}
	}
	for (; ; ) {
		int mx = inf, mxu;
		for (int i = 1; i <= n; i++) {
			if (dis[i] < mx && ! vis[i]) {
				mx = dis[i], mxu = i;
			}
		}
		if (mx == inf) {
			break;
		}
		vis[mxu] = 1;
		for (int v = 1; v <= n; v++) {
			if (mx + p[mxu][v] < dis[v]) {
				dis[v] = mx + p[mxu][v], lst[v] = mxu;
			}
		}
	}
	int val = inf;
	for (int i = 1; i <= n; i++) {
		if ((! z[i]) && dis[i] + w[u][i] < val) {
			val = dis[i] + w[u][i], y = i;
		}
	}
	if (val == inf) {
		return inf;
	}
	for (x = y; lst[x]; x = lst[x]);
	return val;
}
int _solve(int u, int &a, int &b) {
	int ans = inf;
	for (int i = 0; (1 << i) <= n; i++) {
		for (int j = 1; j <= n; j++) {
			z[j] = (j >> i) & 1;
		}
		int x, y;
		int val = dij(u, x, y);
		if (val < ans) {
			ans = val, a = x, b = y;
		}
	}
	return ans;
}
int solve(int u) {
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			p[i][j] = ((i == u || j == u) ? inf : w[i][j]);
		}
	}
	int lv = 0;
	for (int i = 1; i <= n; i++) {
		if (w[u][i] < inf) {
			lv++;
		}
	}
	if (lv < 3) {
		return inf;
	}
	int ans = inf;
	int a, b;
	int s = _solve(u, a, b);
	if (s == inf) {
		return inf;
	}
	for (int i = 1; i <= n; i++) {
		if (i != a && i != b && s + w[u][i] < ans) {
			ans = s + w[u][i];
		}
	}
	int x, y;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			p[i][j] = ((i == u || j == u || i == a || j == a) ? inf : w[i][j]);
		}
	}
	ans = min(ans, _solve(u, x, y) + w[u][a]);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			p[i][j] = ((i == u || j == u || i == b || j == b) ? inf : w[i][j]);
		}
	}
	ans = min(ans, _solve(u, x, y) + w[u][b]);
	return ans;
}
int main() {
	int m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			w[i][j] = inf;
		}
	}
	for (int i = 1; i <= m; i++) {
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		w[x][y] = w[y][x] = z;
	}
	int ans = inf;
	for (int i = 1; i <= n; i++) {
		ans = min(ans, solve(i));
	}
	printf("%d\n", ans == inf ? -1 : ans);
	return 0;
}

标签:Atcoder,ABC308H,val,int,Make,https,短路,dis
From: https://www.cnblogs.com/lhzawa/p/17542202.html

相关文章

  • Atcoder ARC164B Switching Travel
    称\(c_u\not=c_v\)的边\((u,v)\)为普通边,\(c_u=c_v\)的边\((u,v)\)为特殊边。能发现若满足条件则这个环应该是由一条特殊边和若干条普通便组成的(从特殊边的一个顶点出发一直经过普通边,最后走到特殊边的另一个顶点再走回来)。于是若这个特殊边的两个顶点能只通过普通......
  • Python | os.makedirs函数的使用
    概述os.makedirs()方法用于递归创建目录。如果子目录创建失败或者已经存在,会抛出一个OSError的异常,Windows上Error183即为目录已经存在的异常错误。如果第一个参数path只有一级,则mkdir()函数相同。语法makedirs()方法语法格式如下:os.makedirs(path,mode=0o777)参......
  • AtCoder Regular Contest 164 (A-C)
    A.TernaryDecomposition思维难度其实可以作为第二题思路先考虑最优情况下需要多少个数来组成(不够就No)在考虑全部为1的情况下是否可行(N<K这种情况不行)剩下的情况,考虑每次把高位的1向下挪变为3,所需的数字+2那么即三进制拆分后,在[min,max]范围内,且与最优情况差值为......
  • Atcoder ARC159C Permutation Addition
    设\(s=\sum\limits_{i=1}^na_i\),考虑加上排列\(p\),那么\(s\leftarrows+\frac{n\times(n+1)}{2}\)。当有解时,因为\(a_i\)相等,所以有\(s\bmodn=0\)。考虑\(n\bmod2=1\)时,\(\frac{n\times(n+1)}{2}\bmodn=0\),所以\(s\bmodn=0\)时才会有解。......
  • AtCoder Beginner Contest 309
    A:1#include<cstdio>2#include<cstring>3#include<algorithm>4#include<iostream>5#include<string>6#include<vector>7#include<stack>8#include<bitset>9#include<cstdlib>10#include......
  • AtCoder Beginner Contest 273 ABCD
    AtCoderBeginnerContest273A-ARecursiveFunctionProblemStatement题意:给你一个函数\(f(x)\)\(f(0)=1\)对于所有正整数\(k\),有\(f(k)=k*f(k-1)\)找到\(f(N)\)Solution思路:数据范围只有\(10\),直接递归。#include<bits/stdc++.h>usingnamespacestd;typede......
  • AtCoder Beginner Contest 309
    感觉F写了个乱搞做法A-Nine(abc309A)题目大意给定一个\(3\times3\)的网格,以及两个数字。问这两个数字是否水平相邻。解题思路求出两个数字的横纵坐标,看是否横坐标相同,纵坐标差一即可。读题不仔细,开题就WA了。神奇的代码#include<bits/stdc++.h>usingnamespa......
  • vscode makedown md代码片段不生效
    1.创建markdoen代码片段文件。注意文件名:markdown.json2.写代码片段:"多行注释":{ "prefix":"notebash", "body":[ "", "```bash", "", "```", "" ], "description":......
  • AtCoder Grand Contest 058 D Yet Another ABC String
    洛谷传送门AtCoder传送门OrzH6_6Q,感谢他给我们带来了这道容斥好题。这个东西看起来很不好搞。可以尝试容斥。但是我们要容斥啥?钦定ABC不出现,其他任意?感觉还是很难算。观察不合法子串,发现它们很有特点。如果我们钦定\(\texttt{A}\)为\(0\),\(\texttt{B}\)为\(1\),\(\te......
  • AtCoder Beginner Contest 308 题解
    https://atcoder.jp/contests/abc308/tasks_printA-NewScheme过水已隐藏。#include<bits/stdc++.h>#include<ext/pb_ds/assoc_container.hpp>#include<ext/pb_ds/tree_policy.hpp>#include<ext/pb_ds/hash_policy.hpp>usingnamespacestd;u......