AcWing 1194. 岛和桥

时间:2020-05-28
本文章向大家介绍AcWing 1194. 岛和桥,主要包括AcWing 1194. 岛和桥使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

\(f[s][i][j]\) 表示一条有向路径(不经过重复点),当前路径点集合为 \(s\),最后两个点是 \(j\)\(i\) 的最大价值
\(g[s][i][j]\) 类似,不过是方案数。

较为显然的转移,枚举 \(s\) 中的点 \(k (i \not= j \not = k)\)

\(f[s][i][j] = \max(f[s\ \text{xor}\ 2^k][j][k] + a[i] \times a[j] + \text{w}(i,j,k))\)

\(\text{w}(i, j, k)\) 表示 \(i, j, k\) 如果构成一个环的权值,否则为 \(0\)

方案数也是类似的。

初始化两点路径,即 \(f[2^i\ \text{or}\ 2^j][i][j] = a[i] \times a[j]\)

注意方案数最后要 \(/2\),因为会统计两次(我们规定的是有向)

复杂度

\(O(2^n\times n^3)\)\(\text{lowbit}\) 应该还能省复杂度,但是我不会算

注意特判一个节点的时候

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

typedef long long LL;

const int N = 13;

int n, m, a[N], Log[1 << N], sum;

bool w[N][N];

LL f[1 << N][N][N], g[1 << N][N][N];

void out(int x) {
	for (int i = 0; i < n; i++)
		printf("%d", x >> i & 1);
}

void inline clear() {
	memset(w, false, sizeof w);
	memset(g, 0, sizeof g);
	memset(f, 0, sizeof f);
	sum = 0;
}

int main() {
	int T; scanf("%d", &T);
	while (T--) {
		clear();
		scanf("%d%d", &n, &m);
		for (int i = 0; i < n; i++) scanf("%d", a + i), Log[1 << i] = i, sum += a[i];
		for (int i = 1; i <= m; i++) {
			int a, b; scanf("%d%d", &a, &b);
			--a, --b;
			w[a][b] = w[b][a] = true;
		}
		if (n == 1) { printf("%d %d\n", a[0], 1); continue; }
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				if (i != j && w[i][j]) {
					f[(1 << i) | (1 << j)][i][j] = a[i] * a[j];
					g[(1 << i) | (1 << j)][i][j] = 1;	
				}
			}
		}
		for (int s = 1; s < (1 << n); s++) {
			for (int A = s, i = Log[s & -s]; A ; A -= 1 << i, i = Log[A & -A]) {
				for (int B = s ^ (1 << i), j = Log[B & -B]; B; B -= 1 << j, j = Log[B & -B]) {
				    if (!w[i][j]) continue;
					for (int C = s ^ (1 << i) ^ (1 << j), k = Log[C & -C]; C; C -= 1 << k, k = Log[C & -C]) {
						if (!w[j][k] || !f[s ^ (1 << i)][j][k]) continue;
						LL val = f[s ^ (1 << i)][j][k] + a[i] * a[j] + (w[i][k] ? a[i] * a[j] * a[k] : 0);
						if (val > f[s][i][j]) f[s][i][j] = val, g[s][i][j] = g[s ^ (1 << i)][j][k];
						else if (val == f[s][i][j]) g[s][i][j] += g[s ^ (1 << i)][j][k];
					}
				}
			} 
		}
		LL res = 0, cnt = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
			    if (!g[i][j]) continue;
				if (f[(1 << n) - 1][i][j] > res) res = f[(1 << n) - 1][i][j], cnt = g[(1 << n) - 1][i][j];
				else if (f[(1 << n) - 1][i][j] == res) cnt += g[(1 << n) - 1][i][j];
			}
		}
		if (!res) puts("0 0");
		else printf("%lld %lld\n", res + sum, cnt / 2);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/dmoransky/p/12984281.html