• AcWing 1194. 岛和桥


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

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

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

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

    方案数也是类似的。

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

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

    复杂度

    (O(2^n imes n^3))( ext{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
    ", 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
    ", res + sum, cnt / 2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    python eval lmbda
    python函数--day14-03
    深浅拷贝--day14-02
    数据结构与算法--排序
    数据结构与算法--栈(stack)与队列(queue)
    完全背包的计数问题
    [题解] Codeforces Round #568 (Div. 2) C题题解
    [题解] Codeforces Round #640 (Div. 4) C题 题解
    数据结构——程序设计(一)单链表功能的操作与实现
    [题解] Codeforces Round #708 (Div. 2) C1 题解报告
  • 原文地址:https://www.cnblogs.com/dmoransky/p/12984281.html
Copyright © 2020-2023  润新知