zoukankan      html  css  js  c++  java
  • ZOJ 3213 Beautiful Meadow (插头DP 求简单路径)

    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,我用的是最小表示法,感觉最小表示法更加通用一些。

    代码如下:

    有很多需要注意的地方。

    /*
    ZOJ 3213
    */
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    
    const int MAXD=15;
    const int HASH=10007;
    const int STATE=1000010;
    
    int N,M;
    int maze[MAXD][MAXD];
    int code[MAXD];
    int ch[MAXD];
    int num;//独立插头的个数
    int ans;//答案
    
    struct HASHMAP
    {
        int head[HASH],next[STATE],size;
        int state[STATE],dp[STATE];
        void init()
        {
            size=0;
            memset(head,-1,sizeof(head));
        }
        void push(int st,int ans)
        {
            int i,h=st%HASH;
            for(i=head[h];i!=-1;i=next[i])
              if(state[i]==st)
              {
                  if(dp[i]<ans)dp[i]=ans;
                  return;
              }
            state[size]=st;
            dp[size]=ans;
            next[size]=head[h];
            head[h]=size++;
        }
    }hm[2];
    void decode(int *code,int m,int st)
    {
        num=st&7;//独立插头个数
        st>>=3;
        for(int i=m;i>=0;i--)
        {
            code[i]=st&7;
            st>>=3;
        }
    }
    int encode(int *code,int m)
    {
        int cnt=1;
        memset(ch,-1,sizeof(ch));
        ch[0]=0;
        int st=0;
        for(int i=0;i<=m;i++)
        {
            if(ch[code[i]]==-1)ch[code[i]]=cnt++;
            code[i]=ch[code[i]];
            st<<=3;
            st|=code[i];
        }
        st<<=3;
        st|=num;
        return st;
    }
    void shift(int *code,int m)
    {
        for(int i=m;i>0;i--)code[i]=code[i-1];
        code[0]=0;
    }
    void dpblank(int i,int j,int cur)
    {
        int k,left,up;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);
            left=code[j-1];
            up=code[j];
            if(left&&up)
            {
                if(left!=up)
                {
                    code[j-1]=code[j]=0;
                    for(int t=0;t<=M;t++)
                      if(code[t]==up)
                         code[t]=left;
                    if(j==M)shift(code,M);
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
                   // hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]+maze[i][j]);
                }
            }
            else if(left||up)
            {
                int t;
                if(left)t=left;
                else t=up;
                if(maze[i][j+1])
                {
                    code[j-1]=0;
                    code[j]=t;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
                }
                if(maze[i+1][j])
                {
                    code[j-1]=t;
                    code[j]=0;
                   hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]+maze[i][j]);
                }
                if(num<2)
                {
                    num++;
                    code[j-1]=code[j]=0;
                    hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]+maze[i][j]);
                }
            }
            else
            {
                code[j-1]=code[j]=0;
               hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]);
                if(maze[i][j+1]&&maze[i+1][j])
                {
                    code[j-1]=code[j]=13;
                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
                }
                if(num<2)
                {
                    num++;
                    if(maze[i][j+1])
                    {
                        code[j]=13;
                        code[j-1]=0;
                        hm[cur^1].push(encode(code,M),hm[cur].dp[k]+maze[i][j]);
                    }
                    if(maze[i+1][j])
                    {
                        code[j-1]=13;
                        code[j]=0;
                       hm[cur^1].push(encode(code,j==M?M-1:M),hm[cur].dp[k]+maze[i][j]);
                    }
                }
            }
        }
    }
    void dpblock(int i,int j,int cur)
    {
        int k;
        for(k=0;k<hm[cur].size;k++)
        {
            decode(code,M,hm[cur].state[k]);//这个忘记了!!!
            code[j-1]=code[j]=0;
            if(j==M)shift(code,M);
            hm[cur^1].push(encode(code,M),hm[cur].dp[k]);
        }
    }
    void init()
    {
        scanf("%d%d",&N,&M);
        ans=0;
        memset(maze,0,sizeof(maze));//初始化别忘记了
        for(int i=1;i<=N;i++)
          for(int j=1;j<=M;j++)
          {
              scanf("%d",&maze[i][j]);
              if(maze[i][j]>ans)ans=maze[i][j];
          }
    }
    void solve()
    {
        int i,j,cur=0;
        hm[cur].init();
        hm[cur].push(0,0);
        for(i=1;i<=N;i++)
           for(int j=1;j<=M;j++)
           {
               hm[cur^1].init();
               if(maze[i][j])dpblank(i,j,cur);
               else dpblock(i,j,cur);
               cur^=1;
           }
        for(i=0;i<hm[cur].size;i++)
          if(hm[cur].dp[i]>ans)
            ans=hm[cur].dp[i];
        printf("%d\n",ans);
    }
    int main()
    {
      //  freopen("in.txt","r",stdin);
      //  freopen("out.txt","w",stdout);
        int T;
        scanf("%d",&T);
        while(T--)
        {
            init();
            solve();
        }
        return 0;
    }
    
    
    
    /*
    Sample Input
    
    2
    1 1
    10
    1 2
    5 0
    
    Sample Output
    
    10
    5
    
    
    */
    人一我百!人十我万!永不放弃~~~怀着自信的心,去追逐梦想
  • 相关阅读:
    tp5最强分页 自定义model,控制器引用。只显示一页
    tp5分页,一看就懂,简单明了(附带额外参数)
    PHP 验证5-20位数字加字母的正则(数字和字母缺一不可)!!!
    表格样式
    tp5中很牛皮的一句sql语句,三个条件(两个不确定条件,一个硬性条件)
    centos6.8下搭建git和gitlab版本库
    解决 nginx: [alert] kill(1022, 1) failed (3: No such process)
    Zabbix利用msmtp+mutt发送邮件报警
    nginx基本配置与参数说明
    Linux添加/删除用户和用户组
  • 原文地址:https://www.cnblogs.com/kuangbin/p/2710055.html
Copyright © 2011-2022 走看看