1. 程式人生 > >hdu 1693 Eat the Trees 輪廓線 插頭dp

hdu 1693 Eat the Trees 輪廓線 插頭dp

題目連結:

題目意思:

給n*m的方格,有些方格有障礙,問有多少種方式能使所有的非障礙點都在某個環上,環可以有多個。

解題思路:

輪廓線dp.

dp[i][j][s]表示到達第i行第j列,輪廓線上插頭的狀態為s時的總的方案數。

對於當前第j列,狀態(bool) s&(1<<j)表示當前格的右插頭,(bool) s&(1<<(j-1)表示當前格的下插頭。

容易知:

當前格為通行狀態時:00<=11     01<=10,01      10<=10,01     11<=00 

當前格為障礙狀態時:00<=00     其他為0

初始化為dp[0][m][0]=1 ;表示初始狀態

上一行的最後一列的狀態可以左移一位作為下一行的初始狀態。

因為對於每一行的最後一列狀態有效狀態 K0K1K2..Km  Km一定為0,不可能有右插頭

對於每一行的開始一列的前一狀態 K0K1K2..Km K0一定為0,不可能存在第一格的左插頭。

所以可以左移一位,作為下一行的初始狀態。(注意下標從左置右為從小到大)

程式碼:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
using namespace std;

/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
ll dp[15][15][1<<15];
int save[15][15];

int main()
{
   int t,n,m;

   scanf("%d",&t);
   for(int ca=1;ca<=t;ca++)
   {
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++)
         for(int j=1;j<=m;j++)
            scanf("%d",&save[i][j]);
      dp[0][m][0]=1; //初始化狀態
      for(int i=1;i<=n;i++)
      {
         for(int j=0;j<(1<<(m+1));j++)  //換行的時候,只需將狀態左移一位
            dp[i][0][j<<1]=dp[i-1][m][j];//從k0k1k2...k(m-1)0 到0k1k2k3...km,只需左移一位
         for(int j=1;j<=m;j++)
         {
            for(int k=0;k<(1<<(m+1));k++)
            {
               int p=1<<j; //當前格子的右插頭 //分別從上一格子的 相對於當前格子的左插頭和上插頭遞推過來
               int q=p>>1; //當前格子的下插頭
               bool x=k&p; //是否有插頭,將多位轉化為1位
               bool y=k&q; //是否有插頭

               if(save[i][j]) //可通
               {
                  dp[i][j][k]=dp[i][j-1][k^p^q]; //相當於這兩位取反 00<=11
                                                                  //01<=10 10<=01 11<=00
                                                   //對於每個狀態都有一條路聯通,另外01<=01 10<=10
                  if(x!=y) //新增加的情況 10<=10 01<=10
                     dp[i][j][k]+=dp[i][j-1][k];
               }
               else //有障礙物
               {
                  if(x==0&&y==0) //均為0
                     dp[i][j][k]=dp[i][j-1][k]; //前一格子也為0,0,前面一塊可以連通
                  else
                     dp[i][j][k]=0;  //不為0,對於這種狀態只能標誌為0
               }
            }
         }
      }
      printf("Case %d: There are %I64d ways to eat the trees.\n",ca,dp[n][m][0]);
     // printf("%d\n",dp[n][m][0]); //輪廓線為0(沒有插頭)的情況

   }

   return 0;
}



相關推薦

hdu 1693 Eat the Trees 輪廓 插頭dp

題目連結: 題目意思: 給n*m的方格,有些方格有障礙,問有多少種方式能使所有的非障礙點都在某個環上,環可以有多個。 解題思路: 輪廓線dp. dp[i][j][s]表示到達第i行第j列,輪廓線上插頭的狀態為s時的總的方案數。 對於當前第j列,狀態(bool) s&

HDU 1693 Eat the Trees (插頭DP)

tac 回路 ons sign turn algorithm div max ostream 題意:給定一個01矩陣,問你能畫出幾條回路,使得包含所有的1。 析:一個插頭DP,dp[i][j][s] 表示轉移到 (i, j) 這個格子,狀態為 s 時的方案數,然後逐格遞推。

HDU.1693.Eat the Trees(插頭DP)

題目連結 http://www.cnblogs.com/LadyLex/p/7326874.html 插頭DP。對於本題我們只需要記錄之前\(m\)個格子的\(m+1\)個插頭是否存在。 轉移時根據左邊、上邊是否有插頭討論。用位運算可以寫的很方便。 因為想對DP陣列壓壓維,我也覺得寫的好不直觀=-=。反

hdu 1693 Eat the Trees——插頭DP

con sca tree not in mes ret sizeof 插頭dp 二進制 題目:http://acm.hdu.edu.cn/showproblem.php?pid=1693 第一道插頭 DP ! 直接用二進制數表示狀態即可。 #include<

HDU - 1693 Eat the Trees

題面 題意 給出一張網格圖,用多條迴路覆蓋它的所有格子,問有幾種方案。 做法 插頭dp,在輪廓線上維護這些格子是否與下面的格子相連,並且維護當前的格子是否與左邊的格子相連,也就是維護下面箭頭兩端的格子是否相連: 然後只要用

hdu1693 Eat the Trees 插頭dp

i++ vector HERE con rst tun fin 輪廓線 link 題意:有障礙物的多回路的插頭dp,求方案數 題解:其實搞懂插頭dp的插頭方式就和輪廓線dp一樣了,因為這題是多回路,不需要單回路的連通性;‘ dp[i][j]表示第i行j狀態的方案數 需要註意

hdu1693 Eat the Trees插頭dp

分享圖片 技術 esp urn case line 狀態 連通性 cas 題目鏈接 hdu1693 題解 插頭\(dp\) 特點:範圍小,網格圖,連通性 輪廓線:已決策點和未決策點的分界線 插頭:存在於網格之間,表示著網格建的信息,此題中表示兩個網格間是否連邊 狀態表示:當

【HDU1693】Eat the Trees插頭dp

【HDU1693】Eat the Trees(插頭dp) 題面 HDU Vjudge 大概就是網格圖上有些點不能走,現在要找到若干條不相交的哈密頓迴路使得所有格子都恰好被走過一遍。 題解 這題的弱化版本吧。。。 因為可以任意分配哈密頓迴路的數量,因此根本不需要再考慮插頭的配對問題了,那麼直接分情況轉移

luoguP5074 Eat the Trees

https://www.luogu.org/problemnew/show/P5074 插頭 $ dp $ 入門題 如果你還不會插頭 $ dp $ 請右轉 洛谷插頭dp題解 雖然是入門題但還是逃不過分類討論的魔爪 這裡採用了括號序列的方法 $ left $ 表示左插頭的狀態,$ up $ 表示右插頭

HDU 1392 Surround the Trees(凸包)題解

code esp pos con clas tac span bool swa 題意:給一堆二維的點,問你最少用多少距離能把這些點都圍起來 思路: 凸包: 我們先找到所有點中最左下角的點p1,這個點絕對在凸包上。接下來對剩余點按照相對p1的角度升序排序,角度一樣按距離

luogu Eat the Trees

ini long 限制 方法 amp etc con ans sizeof /* 用和模板類似的方法就行 但是實際上弱化版不用考慮匹配情況限制更加寬松, 只需要保存每個位置有無插頭即可, */ #include<cstdio> #include<algo

HDU 5956】The Elder(樹上斜率DP

思路: 樹形DP,dp[i]=min(dp[j]+(sum[i]-sum[j])^2+p)   (j是i的祖先即j<i) ,用斜率將複雜度由O(n^2)優化為O(n)。 此外,在pop的時候可以二分,會更優一些。 但是感覺寫起來有點麻煩,這個題不二分的話,時間

HDU 1565 方格取數(1)(插頭DP||狀態壓縮)

Problem Description 給你一個n*n的格子的棋盤,每個格子裡面有一個非負數。 從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取的數所在的2個格子不能相鄰,並且取出的數的和最大。 Input 包括多個測試例項,每個測試例項包括一

HDU - 4010 Query on The Trees——Link Cut Tree

LCT模板題,link和cut是基本操作 更新一條鏈(u,v)就是做 mroot(u); access(v); splay(v)操作;然後給v打上標記,splay時上下推即可 求一條鏈(u,v)的最小值,同樣做 mroot(u); access(v); splay(v

Campus Design(hdu 4804 輪廓dp

題目連結: Campus Design   題意: 有n*m個格子的矩形,有些格子不能放東西,其餘格子用1*2 、2*1 、1*1的木塊去填充,其中1*1的木塊的使用個數必須>=C且<=D,1*2和2*1的沒有限制,求能把矩形都填滿的方案數。  

插頭輪廓與基於連通性狀態壓縮的dp 學習指南

*插頭,真的插,插了又插* 什麼是插頭dp 像這樣在一個n*m的棋盤上(n與m很小),求有多少種不同的迴路數,或是用1條迴路經過所有點或部分點的方案數,或是求一條路徑上的權值和最大的問題。 通常稱為插頭dp。 這類問題通常很明顯,但程式碼量大又容易出錯,有時TLE有時M

輪廓DP插頭DP 裸 經典骨牌)

引言:所謂輪廓線,不是某一行,或者某一列,而是指某一個特定輪廓的狀態。 放置骨牌的約定:(保證放置有最優子結構) 假設我們正在放置第i行的骨牌,那麼會有下面3種方式: 灰色表示已經有的骨牌,綠色表示新放置的骨牌。 每一種放置方法解釋如下,假設當第i行的狀態為x,第i-

HDU 4930 Fighting the Landlords(扯淡模擬題)

href blank 。。 clear break 輸出 family fig set Fighting the Landlords 大意: 鬥地主。。。。 分別給出兩把手牌,肯定都合法。每張牌大小順序是Y (i.e. colored Joker) &g

[HDU 4344]Mark the Rope(Pollard_rho+Miller_Rabin)

質因數 pre from == mar des last span his Description Eric has a long rope whose length is N, now he wants to mark on the rope with differen

HDU-1556 Color the ball 【差分數組】

前綴 思想 bsp 前綴和 一個 sizeof all 屬於 pri Problem Description N個氣球排成一排,從左到右依次編號為1,2,3....N.每次給定2個整數a b(a <= b),lele便為騎上他的“小飛鴿"牌電動車從氣球a開始到氣球b