zoukankan      html  css  js  c++  java
  • 洛谷P3886 [JLOI2009]神秘的生物(插头dp)

    洛谷P3886 [JLOI2009]神秘的生物(插头dp)

    题目大意

    求带权正方形棋盘中最大权联通块

    数据范围

    [1 le n le 9 ]

    解题思路

    自己做出来的第一道插头 dp,不过很简单就是了

    由于这道题维护的是连通性,所以要用最小表示法记录一下每个点所在的联通块编号,然后就是轮廓线保留 n 个格子即可,因为插头处只用看看左边有没有块

    那么就分为两种情况了,一种是不放插头,一种是放一个插头

    不放插头要看看是不是会导致图不连通,放插头要将左和上的两个格子的联通块合并

    代码

    const int N = 5050;
    const int P = 3592;
    int h[N], ne[N], st[2][N], tot[2], val[2][N], nw, pr;
    void insert(int bit, int num) {
    //	printf ("%d %d
    ", bit, num);
    	int x = bit % P + 1;
    	for (int i = h[x]; i; i = ne[i]) 
    		if (st[nw][i] == bit) return Mx(val[nw][i], num);
    	ne[++tot[nw]] = h[x], st[nw][h[x] = tot[nw]] = bit, val[nw][tot[nw]] = num;
    }
    
    int vis[9], ans = -1e6, n;
    int reb(int bit) {
    	int now = 0, mx = 0;
    	memset(vis, 0, sizeof(vis));
    	for (int i = 0;i < n; i++) {
    		int p = bit >> (i * 3) & 7;
    		if (!p) continue;
    		if (!vis[p]) vis[p] = ++mx;
    		now |= vis[p] << (i * 3);
    	}
    	return now;
    }
    
    void update(int now, int val) {
    	for (int l = 0;l < n; l++)
    		if ((now >> (l * 3) & 7) > 1) return; 
    	Mx(ans, val);
    }
    
    int a[50][50];
    int main() {
    	read(n);
    	for (int i = 1;i <= n; i++)
    		for (int j = 1;j <= n; j++) 
    			read(a[i][j]), Mx(ans, a[i][j]);
    	if (ans <= 0) return write(ans), 0;
    	insert(0, 0); 
    	for (int i = 1;i <= n; i++) {
    		for (int j = 1;j <= n; j++) {
    			pr = nw, nw = nw ^ 1, tot[nw] = 0;
    			memset(h, 0, sizeof(h));
    			for (int k = 1;k <= tot[pr]; k++) {
    				int now = st[pr][k], V = val[pr][k];
    				int b1 = (j == 1) ? 0 : now >> ((j - 2) * 3) & 7; 
    				int b2 = now >> ((j - 1) * 3) & 7;
    				update(now, V);
    				int cc = 0;
    				for (int l = 0;l < n; l++) {
    					int pp = now >> (l * 3) & 7;
    					if (pp == b2) cc++;
    				}
    				if (cc > 1 || b2 == 0) insert(now ^ (b2 << ((j-1) * 3)), V);
    				for (int l = 0;l < n; l++) {
    					int pp = now >> (l * 3) & 7;
    					if (pp == 0) continue;
    					if (pp == b1 || pp == b2) 
    						now ^= (7 ^ pp) << (l * 3);
    				}
    				if (b2 == 0) now |= 7 << ((j-1) * 3);
    				insert(reb(now), V + a[i][j]);
    			}
    		}
    	}
    	for (int i = 1;i <= tot[nw]; i++)
    		update(st[nw][i], val[nw][i]);
    	write(ans);
    	return 0;
    }
    
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 字符串逆序
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 最长字符串
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Java实现 蓝桥杯VIP 算法训练 成绩的等级输出
    Qt 自定义model实现文件系统的文件名排序
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13353508.html
Copyright © 2011-2022 走看看