• 【bzoj2310】ParkII 插头dp


    题目描述

    给你一个 m * n 的矩阵,每个矩阵内有个权值V(i,j) (可能为负数),要求找一条路径,使得每个点最多经过一次,并且经过的点权值之和最大。

    输入

    第一行 m, n,接下来 m行每行 n 个数即 V(i,j)

    输出

    一个整数表示路径的最大权值之和.

    样例输入

    2 3
    1 -2 1
    1 1 1

    样例输出

    5


    题解

    插头dp,神奇游乐园 的进阶版。

    陈丹琦的论文 最后有讲这种路径而非回路的做法。

    与回路相比,在每个状态中添加了至多两个独立插头,表示这个插头没有与其它插头相连,独立存在。在括号序列中既不作为 '(' 也不作为 ')' 。

    普通转移与回路一样,带独立插头的特殊转移有如下几种:

    左无插头、上无插头时,可以新建下或右独立插头;
    左有独立插头、上无插头时,可以选择向下或向右传递这个独立插头;左无插头、上有独立插头时同理;
    左有独立插头、上有非独立插头时,连接两个插头,并将上插头的另一端改为独立插头;左有非独立插头、上有独立插头时同理。

    更新答案的时机:

    左/上有独立插头,其余处均无插头时更新答案,此时路径的一个端点为当前格子,另一个端点在独立插头的另一端;
    左、上均有独立插头,其余处均无插头时更新答案,此时路径的一个端点为左独立插头的另一端,另一个端点为上独立插头的另一端。
    注意这两种情况不能更新状态。

    然后就是大量的if判断吧。。。呵呵呵。。。

    注意特判路径只有一个点的情况(尽管不判断也能过。。。)

    #include <cstdio>
    #include <cstring>
    int m , a[110][9] , w[263000] , v[8500] , tot , f[110][9][8500];
    inline int pos(int a , int i)
    {
    	return a << (i << 1);
    }
    inline void gmax(int &a , int b)
    {
    	a = (a > b ? a : b);
    }
    void dfs(int p , int c , int k , int now)
    {
    	if(k > 2 || c < 0 || c > m - p + 1) return;
    	if(p > m)
    	{
    		w[now] = ++tot , v[tot] = now;
    		return;
    	}
    	dfs(p + 1 , c , k , now);
    	dfs(p + 1 , c + 1 , k , now + (1 << (p << 1)));
    	dfs(p + 1 , c - 1 , k , now + (2 << (p << 1)));
    	dfs(p + 1 , c , k + 1 , now + (3 << (p << 1)));
    }
    inline int l(int v , int p)
    {
    	int i , c = 0;
    	for(i = p ; ~i ; i -- )
    	{
    		if(((v >> (i << 1)) & 3) == 1) c -- ;
    		if(((v >> (i << 1)) & 3) == 2) c ++ ;
    		if(!c) return i;
    	}
    	return -1;
    }
    inline int r(int v , int p)
    {
    	int i , c = 0;
    	for(i = p ; i <= m ; i ++ )
    	{
    		if(((v >> (i << 1)) & 3) == 1) c ++ ;
    		if(((v >> (i << 1)) & 3) == 2) c -- ;
    		if(!c) return i;
    	}
    	return -1;
    }
    int main()
    {
    	int n , i , j , k , s , p , q , ans = -1 << 30;
    	scanf("%d%d" , &n , &m);
    	dfs(0 , 0 , 0 , 0);
    	for(i = 1 ; i <= n ; i ++ )
    		for(j = 1 ; j <= m ; j ++ )
    			scanf("%d" , &a[i][j]);
    	memset(f , 0xc0 , sizeof(f)) , f[1][0][w[0]] = 0;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		for(j = 1 ; j <= m ; j ++ )
    		{
    			if(ans < a[i][j]) ans = a[i][j];
    			for(k = 1 ; k <= tot ; k ++ )
    			{
    				p = (v[k] >> ((j - 1) << 1)) & 3 , q = (v[k] >> (j << 1)) & 3 , s = f[i][j - 1][k] + a[i][j];
    				if(!p && !q)
    				{
    					gmax(f[i][j][k] , f[i][j - 1][k]);
    					if(j < m) gmax(f[i][j][w[v[k] ^ pos(3 , j)]] , s);
    					if(i < n) gmax(f[i][j][w[v[k] ^ pos(3 , j - 1)]] , s);
    					if(i < n && j < m) gmax(f[i][j][w[v[k] ^ pos(1 , j - 1) ^ pos(2 , j)]] , s);
    				}
    				if(!p && q)
    				{
    					if(j < m) gmax(f[i][j][k] , s);
    					if(i < n) gmax(f[i][j][w[v[k] ^ pos(q , j) ^ pos(q , j - 1)]] , s);
    					if(q == 1) gmax(f[i][j][w[v[k] ^ pos(1 , j) ^ pos(1 , r(v[k] , j))]] , s);
    					if(q == 2) gmax(f[i][j][w[v[k] ^ pos(2 , j) ^ pos(2 , l(v[k] , j))]] , s);
    					if(q == 3 && !(v[k] ^ pos(3 , j))) gmax(ans , s);
    				}
    				if(p && !q)
    				{
    					if(i < n) gmax(f[i][j][k] , s);
    					if(j < m) gmax(f[i][j][w[v[k] ^ pos(p , j - 1) ^ pos(p , j)]] , s);
    					if(p == 1) gmax(f[i][j][w[v[k] ^ pos(1 , j - 1) ^ pos(1 , r(v[k] , j - 1))]] , s);
    					if(p == 2) gmax(f[i][j][w[v[k] ^ pos(2 , j - 1) ^ pos(2 , l(v[k] , j - 1))]] , s);
    					if(p == 3 && !(v[k] ^ pos(3 , j - 1))) gmax(ans , s);
    				}
    				if(p == 2 && q == 1) gmax(f[i][j][w[v[k] ^ pos(2 , j - 1) ^ pos(1 , j)]] , s);
    				if(p == 3 && q == 2) gmax(f[i][j][w[v[k] ^ pos(3 , j - 1) ^ pos(2 , j) ^ pos(2 , l(v[k] , j))]] , s);
    				if(p == 1 && q == 3) gmax(f[i][j][w[v[k] ^ pos(1 , j - 1) ^ pos(3 , j) ^ pos(1 , r(v[k] , j - 1))]] , s);
    				if((p == 1 || p == 3) && q == 1) gmax(f[i][j][w[v[k] ^ pos(p , j - 1) ^ pos(1 , j) ^ pos(p ^ 2 , r(v[k] , j))]] , s);
    				if(p == 2 && (q == 2 || q == 3)) gmax(f[i][j][w[v[k] ^ pos(2 , j - 1) ^ pos(q , j) ^ pos(q ^ 1 , l(v[k] , j - 1))]] , s);
    				if(p == 3 && q == 3 && !(v[k] ^ pos(3 , j - 1) ^ pos(3 , j))) gmax(ans , s);
    			}
    		}
    		for(j = 1 ; j <= tot ; j ++ )
    			if(!(v[j] & 3))
    				f[i + 1][0][j] = f[i][m][w[v[j] >> 2]];
    	}
    	printf("%d
    " , ans);
    	return 0;
    }
    
  • 相关阅读:
    如何实现数据库实体生成工具
    linux samba 与 Windows 共享文件
    CUnit 的使用
    Xml Document与 xml反序列化
    c语言多文件链接
    c 递归获取文件与目录
    gdb输入输出重定向
    C 链表实现
    Log4net多程序集使用独立的配置文件
    Sqlite 学习 编译sqlite静态库,供其他项目调用
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8133771.html
Copyright © 2020-2023  润新知