poj3133 插头dp

#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
#include <algorithm>
using namespace std;
const int INF=100000000;
int nrows,ncols;
int G[10][10];
struct State
{
   int up[9];
   int left;
   int encode()const
   {
     int key=left;
     for(int i=0; i<ncols; i++)
        key=key*3+up[i];
     return key;
   }
   bool next(int row, int col, int U, int D, int L, int R, State &T)const
   {
       if( row==nrows-1 && D != 0) return false; //最下行不能有向下的插头
       if( col==ncols-1 && R !=0 ) return false; //最右列右边不能有插头
       int must_left=(col>0&&left!=0);// 是否必须要左插头
       int must_up =(row>0&&up[col]!=0);//是否必须要右插头
       if((must_left!=0 && L!=left ) || (must_left==0 && L!=0 )) return false;//左插头不匹配
       if((must_up  !=0 && U!=up[col])||(must_up==0 && U!=0 ) ) return false;//上插头不匹配
       if(must_left && must_up && left!=up[col]) return false;

       for(int i=0; i<ncols; i++)T.up[i]=up[i];
       T.up[col]=D;
       T.left=R;
      return true;
   }
};
int memo[9][9][59049];
int rec(int row, int col, const State &S)
{
    if(col==ncols){ col=0; row++;};
    if(row==nrows)return 0;
    int key=S.encode();
    int &res = memo[row][col][key];
    if(res>=0)return res;
    res=INF;
    State T;
    if(G[row][col]<=1)
    {
        if(S.next(row,col,0,0,0,0,T))res=min(res,rec(row,col+1,T));
        if(G[row][col]== 0)
            for(int t=1; t<=2 ; t++)
            {
                if(S.next(row,col,t,t,0,0,T))res=min(res,rec(row,col+1,T)+2);
                if(S.next(row,col,t,0,t,0,T))res=min(res,rec(row,col+1,T)+2);
                if(S.next(row,col,t,0,0,t,T))res=min(res,rec(row,col+1,T)+2);
                if(S.next(row,col,0,t,t,0,T))res=min(res,rec(row,col+1,T)+2);
                if(S.next(row,col,0,t,0,t,T))res=min(res,rec(row,col+1,T)+2);
                if(S.next(row,col,0,0,t,t,T))res=min(res,rec(row,col+1,T)+2);
            }

    }
    else {
        int t=G[row][col]-1;
        if(S.next(row,col,t,0,0,0,T))res=min(res,rec(row,col+1,T)+1);
        if(S.next(row,col,0,t,0,0,T))res=min(res,rec(row,col+1,T)+1);
        if(S.next(row,col,0,0,t,0,T))res=min(res,rec(row,col+1,T)+1);
        if(S.next(row,col,0,0,0,t,T))res=min(res,rec(row,col+1,T)+1);
    }
    return res;
}
int main()
{
    while(scanf("%d%d",&nrows,&ncols)==2&&nrows&&ncols)
    {
        for(int i=0; i<nrows; i++)
            for(int j=0; j<ncols; j++)
            scanf("%d",&G[i][j]);
        State S;
        memset(&S,0,sizeof(S));
        memset(memo,-1,sizeof(memo));
        int ans=rec(0,0,S);
        if(ans==INF)ans=0;
        printf("%d\n",ans/2);
    }
    return 0;
}

时间: 2024-11-08 18:17:45

poj3133 插头dp的相关文章

poj3133之经典插头DP

Manhattan Wiring Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 1482   Accepted: 869 Description There is a rectangular area containing n × m cells. Two cells are marked with "2", and another two with "3". Some cells are

初探插头dp

开学那个月学了点新东西,不知道还记不记得了,mark一下 感觉cdq的论文讲的很详细 题主要跟着kuangbin巨做了几道基础的 http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710343.html 还有几道没做,留着坑 感觉广义括号表示法虽然神奇,但一般最小表示法就够用了吧,感觉最小表示法更直观一点 hdu1693 1 #include<cstdio> 2 #include<iostream> 3 #include<

插头dp

对于网格中的dp可以用轮廓线,如果有一些格子不能走就可以用插头dp了. bzoj2331 地板 题目大意:用L型铺地n*m,有一些格子不能铺,求方案数. 思路:fi[i][j][s]表示铺到(i,j),轮廓线状态s,0表示没有插头,1表示插头没拐弯,2表示插头拐弯了,手动枚举转移. 注意:(1)按四进制好写: (2)因为实际状态和四进制的差很多,所以用hash表来存储,防止mle和tle,同时使用滚动数组. #include<iostream> #include<cstdio> #

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数

插头DP学习

队内没人会插头DP,感觉这个不会不行...所以我还是默默去学了一下, 学了一天,感觉会了一点.对于每一行,一共有j+1个插头,如果是多回路类的题目, 比较简单,可以用1表示有插头,0表示没有插头,这样就可以愉快转移了, 对于当前出来的位置(i,j),与它有关的插头有j-1和j 那么我们可以枚举状态经行转移. 对于单回路的问题....只是了解思想,目前还不会写,太笨了=_= poj 2411 Mondriaan's Dream 题意:用1*2小方块组成n*m矩阵有多少种组成方式 思路:我们从上到下

BZOJ 2595 游览计划(插头DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2595 题意:给出一个数字矩阵.求一个连通块包含所有的数字0且连通块内所有数字之和最小. 思路:对于每个格子,是0则必须要选.那么对于不选的格子(i,j)在什么时候可以不选呢?必须同时满足以下两个条件: (1)(i,j)不是0: (2)(i-1,j)不选或者(i-1,j)选了但是轮廓线上还有别的地方与(i-1,j)是一个连通块. int Pre[105][N],op[105][N]; s

【插头dp】CDOJ1690 这是一道比CCCC简单题难的简单题

最裸的插头dp,可参见大白书. #include<cstdio> #include<cstring> using namespace std; #define MOD 1000000007 int f[2][(1<<5)+10],n,m; int main(){ scanf("%d%d",&n,&m); int cur=0; f[0][(1<<m)-1]=1; for(int i=0;i<n;++i){ for(in

POJ 2411 Mondriaan&#39;s Dream ——状压DP 插头DP

[题目分析] 用1*2的牌铺满n*m的格子. 刚开始用到动规想写一个n*m*2^m,写了半天才知道会有重复的情况. So Sad. 然后想到数据范围这么小,爆搜好了.于是把每一种状态对应的转移都搜了出来. 加了点优(gou)化(pi),然后poj上1244ms垫底. 大概的方法就是考虑每一层横着放的情况,剩下的必须竖起来的情况到下一层取反即可. 然后看了 <插头DP-从入门到跳楼> 这篇博客,怒抄插头DP 然后16ms了,自己慢慢YY了一下,写出了风(gou)流(pi)倜(bu)傥(tong)

HDU 4113 Construct the Great Wall(插头dp)

好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm-icpc信息站发现难得的一篇题解.不过看到是插头二字之后,代码由于风格太不一样就没看了,自己想了好久,想通了.然后就等到今天才码.... 如果把点看成网格,那就可以实现,没有公共点公共边等限定条件,也显然是插头dp的最短单回路的模型.这是本题的一个难点(当时想到这样是因为,题目要求计算最短周长,显然