HDU 1693 Eat the Trees (插头DP)

题意:给一个n*m的矩阵,为1时代表空格子,为0时代表障碍格子,问如果不经过障碍格子,可以画一至多个圆的话,有多少种方案?(n<12,m<12)

思路:

  以一个非障碍格子为单位进行DP转移,所以可以用滚动数组。只需要保存m+1个插头的状态,其中有一个是右插头,其他都是下插头,若有插头的存在,该位为1,否则为0,初始时都是0。

  需要考虑的是,(1)如果两个边缘都是插头,那么必须接上它们;(2)如果仅有一边是插头,则延续插头,可以有两个延续的方向(下和右);(3)如果都没有插头,那么必须另开两个新插头(新连通分量)。

  如下图,记录的状态是:101111。由于是按行来保存状态的,第一个格子需要特殊考虑,将所有状态左移一位,最后的一位就是右方向的边缘。假设上行都有下插头,那么此行初始时是011111,可以看到最左边的是0,表示无右插头,注意:我是按照111110保存的,即最低位是最左边。

  

  初始格子dp[0][0]=1,而答案就是dp[cur][0]了,肯定是无插头存在的状态了,所有的圆圈都是完整的。

 1 #include <bits/stdc++.h>
 2 #define pii pair<int,int>
 3 #define INF 0x3f3f3f3f
 4 #define LL long long
 5 using namespace std;
 6 const int N=13;
 7 int g[N][N], cur;
 8 LL dp[N][1<<N];
 9
10 void clear()
11 {
12     cur^=1;
13     memset(dp[cur], 0, sizeof(dp[cur]));
14 }
15
16 LL cal(int n,int m)
17 {
18     dp[0][0]=1;   //开始时没有任何插头
19     for(int i=0; i<n; i++)  //枚举格子
20     {
21         clear();
22         for(int k=0; k<(1<<m); k++)    dp[cur][k<<1]+=dp[cur^1][k];    //最高位自动会被忽略
23         for(int j=0; j<m; j++)
24         {
25             int r=(1<<j), d=(1<<(j+1));         //r和d 相当于 右和下
26             clear();
27             for(int k=0; k<(1<<(m+1)); k++)            //枚举状态
28             {
29                 if(g[i][j])     //空格
30                 {
31                     if( (k&r) && (k&d) )        //两边都有插头:连起来,变无插头
32                         dp[cur][k^r^d]+=dp[cur^1][k];
33                     else if( k&r || k&d )       //其中一边有插头:可转两个方向
34                     {
35                         dp[cur][k]+=dp[cur^1][k];
36                         dp[cur][k^r^d]+=dp[cur^1][k];
37                     }
38                     else                        //无插头:另开两个新插头
39                         dp[cur][k|r|d]=dp[cur^1][k];
40                 }
41                 else       //障碍格子
42                 {
43                     if( !(k&r) && !(k&d) )
44                         dp[cur][k]=dp[cur^1][k];
45                 }
46             }
47         }
48     }
49     return dp[cur][0];
50 }
51
52 int main()
53 {
54     //freopen("input.txt", "r", stdin);
55     int n, m, t, Case=0;
56     cin>>t;
57     while(t--)
58     {
59         scanf("%d%d",&n,&m);
60         memset(g, 0, sizeof(g));
61         memset(dp, 0, sizeof(dp));
62         for(int i=0; i<n; i++)
63             for(int j=0; j<m; j++)
64                 scanf("%d",&g[i][j]);
65         printf("Case %d: There are %lld ways to eat the trees.\n", ++Case, cal(n,m));
66     }
67     return 0;
68 }

AC代码

时间: 2024-10-08 20:39:53

HDU 1693 Eat the Trees (插头DP)的相关文章

HDU 1693 Eat the Trees 插头DP

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1693 题意:给出一块r*c的地,(r,c<=11),其中有的土地上种上了树,有些没有种上树,只能在种上树的地上走,通过走若干个回路,来走遍所有种树的土地.问有多少种走法. 思路:无论如何还是要先提供一个链接:http://wenku.baidu.com/view/4fe4ac659b6648d7c1c74633.html,是国家队论文,里面对于要提及的概念讲解的十分清楚. dp的过程是从左上角的点到右下

[Hdu 1693] Eat the Trees 轮廓线DP

题意 n * m 的矩形, 有坏点, 求划分成若干个回路的方案数. n, m <= 11 . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #define F(i, a, b) for (register int i = (a); i <= (b); i++) 6 #define LL long long 7 inlin

hdu 1693 Eat the Trees (插头dp入门)

Eat the Trees Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2507    Accepted Submission(s): 1225 Problem Description Most of us know that in the game called DotA(Defense of the Ancient), Pudg

【插头DP】HDU 1693 Eat the Trees

通道:http://acm.hdu.edu.cn/showproblem.php?pid=1693 题意:多回路路径方案数,无障碍. 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int MAX_N = 13; 8 const int MAX_M = 13; 9 const int HASH = 10007; 1

HDU - 1693 Eat the Trees(多回路插头DP)

题目大意:要求你将所有非障碍格子都走一遍,形成回路(可以多回路),问有多少种方法 解题思路: 参考基于连通性状态压缩的动态规划问题 - 陈丹琦 以下为代码 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define N 12 #define S (1 << 12) int n, m; long long dp[N][N][S]; int cas = 1

[hdu1693 Eat the Trees]插头dp

题意:用若干条回路覆盖01矩阵里面所有的1的方案数 方法:多回路问题,需要将插头的有无加入状态里,然后沿轮廓线转移即可.简单好写. #include <bits/stdc++.h> using namespace std; #ifndef ONLINE_JUDGE #include "local.h" #endif // ONLINE_JUDGE #define pb(x) push_back(x) #define mp(x, y) make_pair(x, y) #def

HDU 1693 Eat the Trees

Problem Description Most of us know that in the game called DotA(Defense of the Ancient), Pudge is a strong hero in the first period of the game. When the game goes to end however, Pudge is not a strong hero any more.So Pudge’s teammates give him a n

HDU 4804 Campus Design(插头DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4804 题意:给定一个图,0是不能放的,然后现在有1X1和1X2方块,最后铺满该图,使得1X1使用次数在C到D之间,1X2次数随便,问有几种放法 思路:插头DP的变形,只要多考虑1X1的情况即可,然后DP多开一维表示使用1X1的个数 代码: #include <stdio.h> #include <string.h> #include <algorithm> #include

【HDU】1693 Eat the Trees

http://acm.hdu.edu.cn/showproblem.php?pid=1693 题意:n×m的棋盘求简单回路(可以多条)覆盖整个棋盘的方案,障碍格不许摆放.(n,m<=11) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; struct H { static const int M=1000007;