热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

zoj3213(插头DP一条路径)

BeautifulMeadowTimeLimit:5SecondsMemoryLimit:32768KBTomsMeadow

 

Beautiful Meadow
Time Limit: 5 Seconds       Memory Limit: 32768 KB

Tom's Meadow

Tom has a meadow in his garden. He divides it into N * M squares. Initially all the squares are covered with grass and there may be some squares cannot be mowed.(Let's call them forbidden squares.) He wants to mow down the grass on some of the squares. He must obey all these rules:

1 He can start up at any square that can be mowed. 
2 He can end up at any square that can be mowed.
3 After mowing one square he can get into one of the adjacent squares. 
4 He cannot get into any of the forbidden squares.
5 He cannot get into the squares that he has already mowed.
6 If he is in some square he must mow it first. (and then decide whether to mow the adjacent squares or not.)
7 Each square that can be mowed has a property D called beauty degree (D is a positive integer) and if he mowed the square the beauty degree of the meadow would increase by D.
8 Note that the beauty degree of the meadow is 0 at first.
9 Of course he cannot move out of the meadow. (Before he decided to end.)
Two squares are adjacent if they share an edge.

Here comes the problem. What is the maximum beauty degree of the meadow Tom can get without breaking the rules above.

Input

This problem has several test cases. The first line of the input is a single integer T (1 <= T <60) which is the number of test cases. T consecutive test cases follow. The first line of each test case is a single line containing 2 integers N (1 <= N <8) and M (1 <= M <8) which is the number of rows of the meadow and the number of columns of the meadow. Then N lines of input describing the rows of the meadow. Each of the N lines contains M space-separated integers D (0 <= D <= 60000) indicating the beauty degree of the correspoding square. For simplicity the beauty degree of forbidden squares is 0. (And of course Tom cannot get into them or mow them.)

Output

For each test case output an integer in a single line which is maximum beauty degree of the meadow at last.

Sample Input

2
1 1
10
1 2
5 0

Sample Output

10
5

 

Author: CAO, Peng
Source: ZOJ Monthly, June 2009

‍‍分析:这一为插头DP简单路径,一直写一条回路的插头DP,做这题时,本以为只要在原来的基础上加上空插头和一些讨论,事实如此,不过讨论情况之多,实在是难以接受,wa了一次,参考傻崽的代码发现少了几种讨论(我原来以为不是必须的),哎。。。还是那个模板,这回比较慢了,看来有必要优化一下work()函数,哎~~~

代码:

#include
#include
using namespace std;
const int mm=10007;
struct data
{
    int s[mm],h[mm],p[mm],t,d[mm];
    int hash(int x,int dd)
    {
        int i,c=x%mm;
        for(i=h[c];i>=0;i=p[i])
        if(s[i]==x)
        {
            if(dd>d[i])d[i]=dd;
            return i;
        }
        s[t]=x,p[t]=h[c],h[c]=t,d[t]=dd;
        return t++;
    }
    void clear()
    {
        t=0,memset(h,-1,sizeof(h));
    }
}f[2];
int i,j,g1,g2,u,k,n,m,a,b,a1,a2,b1,b2,g[13][13],ans;
int eat(int s,int a,int b,int c,bool f,bool l)
{
    int n=1,x;
    while(n)
    {
        if(f)a<<=2,b<<=2,c<<=2;
        else a>>=2,b>>=2,c>>=2;
        x=s&c;
        if(x==a)++n;
        if(x==b)--n;
    }
    if(l)return (s^b)|a;else return s|c;
}
void work(int S,int d)
{
    int x,y,dd=d+g[i][j];
    x=a&S,y=b&S;
    if(x==0&&y==0)//两个空插头
    {
        if(g[i+1][j]&&g[i][j+1])f[g2].hash(S|a1|b2,dd);
        if(g[i+1][j])f[g2].hash(S|a,dd);
        if(g[i][j+1])f[g2].hash(S|b,dd);
        f[g2].hash(S,d);
    }
    else if(x==0&&y==b)//右插头为空,下插头为独立插头
    {
        if(g[i][j+1])f[g2].hash(S,dd);
        if(g[i+1][j])f[g2].hash((S^b)|a,dd);
        if((S^b)==0&&dd>ans)ans=dd;
    }
    else if(x==a&&y==0)//下插头为空,右插头为独立插头

    {
        if(g[i+1][j])f[g2].hash(S,dd);
        if(g[i][j+1])f[g2].hash((S^a)|b,dd);
        if((S^a)==0&&dd>ans)ans=dd;
    }
    else if(x==0&&y==b1)//右插头为空,下插头为左括号插头
    {
        if(g[i][j+1])f[g2].hash(S,dd);
        if(g[i+1][j])f[g2].hash((S^b1)|a1,dd);
        f[g2].hash(eat(S^b1,b1,b2,b,1,0),dd);
    }
    else if(x==a1&&y==0)//下插头为空,右插头为左括号插头
    {
        if(g[i+1][j])f[g2].hash(S,dd);
        if(g[i][j+1])f[g2].hash((S^a1)|b1,dd);
        f[g2].hash(eat(S^a1,a1,a2,a,1,0),dd);
    }
    else if(x==0&&y==b2)//右插头为空,下插头为右括号插头
    {
        if(g[i][j+1])f[g2].hash(S,dd);
        if(g[i+1][j])f[g2].hash((S^b2)|a2,dd);
        f[g2].hash(eat(S^b2,b2,b1,b,0,0),dd);
    }
    else if(x==a2&&y==0)//下插头为空,右插头为右括号插头
    {
        if(g[i+1][j])f[g2].hash(S,dd);
        if(g[i][j+1])f[g2].hash((S^a2)|b2,dd);
        f[g2].hash(eat(S^a2,a2,a1,a,0,0),dd);
    }
    else if(x==a1&&y==b)f[g2].hash(eat(S^a1^b,a1,a2,a,1,0),dd);//下插头为独立插头,右插头为左括号插头
    else if(x==a2&&y==b)f[g2].hash(eat(S^a2^b,a2,a1,a,0,0),dd);//下插头为独立插头,右插头为右括号插头
    else if(x==a&&y==b1)f[g2].hash(eat(S^a^b1,b1,b2,b,1,0),dd);//右插头为独立插头,下插头为左括号插头
    else if(x==a&&y==b2)f[g2].hash(eat(S^a^b2,b2,b1,b,0,0),dd);//右插头为独立插头,下插头为右括号插头
    else if(x==a1&&y==b1)f[g2].hash(eat(S^a1^b1,b1,b2,b,1,1),dd);//下插头 右插头为左括号插头
    else if(x==a2&&y==b2)f[g2].hash(eat(S^a2^b2,a2,a1,a,0,1),dd);//下插头 右插头为右括号插头
    else if(x==a2&&y==b1)f[g2].hash(S^a2^b1,dd);//右插头为右括号插头,下插头为左括号插头
    else if(x==a&&y==b&&(S^a^b)==0&&dd>ans)ans=dd;//下插头 右插头为独立插头
}
int DP()
{
    f[0].clear();
    f[0].hash(0,0);
    for(--n,--m,g1=1,g2=i=0;i<=n;++i)
    {
        for(k=0;kans)ans=g[i][j];
            }
        printf("%d/n",DP());
    }
    return 0;
}


 更新一下代码:

#include
#include
#define mm 100007
#define mn 11
#define getRP(a,b) ((a)<<((b)<<1))
struct hash
{
    int h[mm],s[mm],p[mm],d[mm],t;
    int push(int x,int v)
    {
        int i,c=x%mm;
        for(i=h[c];i>=0;i=p[i])
        if(s[i]==x)
        {
            if(v>d[i])d[i]=v;
            return i;
        }
        d[t]=v,s[t]=x,p[t]=h[c],h[c]=t;
        return t++;
    }
    void clear()
    {
        t=0;
        memset(h,-1,sizeof(h));
    }
}f[2];
int g[mn][mn];
int i,j,k,g1,g2,x,y,z,s,n,m,ans;
int eat(bool f,bool l)
{
    int a=getRP(z,j+f),b=getRP(3^z,j+f),c=getRP(3,j+f),n=1;
    s=s^getRP(x,j)^getRP(y,j+1);
    while(n)
    {
        if(f)a<<=2,b<<=2,c<<=2;
        else a>>=2,b>>=2,c>>=2;
        x=s&c;
        if(x==a)++n;
        if(x==b)--n;
    }
    return l?(s|c):((s^b)|a);
}
bool ok(int c)
{
    if(c==1)return g[i+1][j];
    if(c==2)return g[i][j+1];
    if(c==3)return g[i+1][j]&&g[i][j+1];
    return 0;
}
void move(int v)
{
    int w=v+g[i][j];
    if(!x&&!y)
    {
        if(ok(1))f[g2].push(s|getRP(3,j),w);
        if(ok(2))f[g2].push(s|getRP(3,j+1),w);
        if(ok(3))f[g2].push(s|getRP(9,j),w);
        f[g2].push(s,v);
    }
    else if(!x||!y)
    {
        z=x+y;
        if(ok(x?1:2))f[g2].push(s,w);
        if(ok(x?2:1))f[g2].push(s^getRP(z,j)^getRP(z,j+1),w);
        if(z<3)f[g2].push(eat(z==1,1),w);
        else if((s^getRP(x,j)^getRP(y,j+1))==0&&w>ans)ans=w;
    }
    else if(x==y)
    {
        if((z=x)<3)f[g2].push(eat(z==1,0),w);
        else if((s^getRP(x,j)^getRP(y,j+1))==0&&w>ans)ans=w;
    }
    else if(x>2||y>2)
    {
        z=x>(j<<1))&3,y=(s>>((j+1)<<1))&3;
                move(f[g1].d[k]);
            }
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(g,0,sizeof(g));
        for(ans=i=0;ians)ans=g[i][j];
            }
        printf("%d\n",PlugDP());
    }
    return 0;
}



推荐阅读
  • 本文介绍了一道经典的状态压缩题目——关灯问题2,并提供了解决该问题的算法思路。通过使用二进制表示灯的状态,并枚举所有可能的状态,可以求解出最少按按钮的次数,从而将所有灯关掉。本文还对状压和位运算进行了解释,并指出了该方法的适用性和局限性。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • 本文介绍了在C#中SByte类型的GetHashCode方法,该方法用于获取当前SByte实例的HashCode。给出了该方法的语法和返回值,并提供了一个示例程序演示了该方法的使用。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
author-avatar
沉醉在温柔箱
这个家伙很懒,什么也没留下!
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有