1. 程式人生 > >HDU 1438  鑰匙計數之一 (狀態壓縮或遞推)

HDU 1438  鑰匙計數之一 (狀態壓縮或遞推)

HDU 1438  鑰匙計數之一  

Problem Description

一把鎖匙有N個槽,槽深為1,2,3,4。每鎖匙至少有3個不同的深度且至少有1對相連的槽其深度之差為3。求這樣的鎖匙的總數。

Input

本題無輸入

Output

對N>=2且N<=31,輸出滿足要求的鎖匙的總數。

Sample Output

N=2: 0 N=3: 8 N=4: 64 N=5: 360 .. .. .. .. .. .. .. N=31: ...

分析:

遞推規律,也找不到,下面有參考大佬的規律遞推

狀態壓縮解法也看了好久才看懂,狀態壓縮有點巧妙啊

#include<iostream>
#include<cstring>
using namespace std;
const int N=40;
long long dp[N][N][N][2];
///第幾個槽,前面槽的狀態(包含幾個不同的深度),最後一個槽的深度,是否已經符合要求
int num[17];
int main()
{
  memset(num,0,sizeof(num));
  memset(dp,0,sizeof(dp));
  for(int i=0;i<16;i++)
    for(int j=0;j<4;j++)
    if(i&(1<<j))
    	num[i]++;///找不同的狀態不同深度數。從而找出合法的至少有3個深度不同
 
  for(int i=0;i<4;i++)///初始化1只有1,2,3,4四個狀態。
    dp[1][1<<i][i][0]=1;
    
  for(int i=2;i<32;i++)///槽數
    for(int j=0;j<16;j++)///不同深度狀態
       for(int k=0;k<4;k++)///前一個槽的最後一個深度
  {
    for(int l=0;l<4;l++)///當前槽的最後一個的深度
    {
      int cur=j|(1<<l);  ///在j的二進位制中第l位變為1(注意從後往前)
     
      dp[i][cur][l][1]+=dp[i-1][j][k][1];
      
      if(k-l==3||k-l==-3)
      {
        dp[i][cur][l][1]+=dp[i-1][j][k][0];
      }
      else dp[i][cur][l][0]+=dp[i-1][j][k][0];
    }
  }
  
  for(int i=2;i<32;i++)
  { long long ans=0;
  
    for(int j=0;j<16;j++)
	 if(num[j]>=3)///挑出符合條件的超過2個不同深度
      for(int k=0;k<4;k++)
      ans+=dp[i][j][k][1];
      
      cout<<"N="<<i<<": "<<ans<<"\n";
  }
}

又是一題遞推題,用遞推的思路去解。 說來慚愧,做這題的時候有個地方卡住了,直到看了別人的解題報告才豁然開朗(數學沒學好。。) 將lock[n]計做n個凹槽時,符合要求的鑰匙總數. 將one[n]計做n個凹槽時,第n個凹槽為1時符合要求的鑰匙總數. 將two[n]計做n個凹槽時,第n個凹槽為2時符合要求的鑰匙總數. 且1=4,2=3; 對與第n個凹槽,有兩種情況。  1.前n-1個凹槽以構成鑰匙,那麼對於第n個凹槽而言,無論第n個凹槽為1/2/3/4,都有lock[n-1]種情況。  2.前n-1個凹槽未構成鑰匙,加了第n個凹槽後才符合鑰匙規則,那麼分兩種情況 A.當第n個凹槽為 2/3時,前面n-1個凹槽必須為1/4構造而成的,出去兩種全為1/4的情況,即2^(n-1)-2種情況 B.當第n個凹槽為1/4時,前面n-1個凹槽的構成有多種情況,將這多種情況分析清楚: 假設第n個凹槽為1: 則前面n-1個凹槽的構成情況有如下幾種 { A1.前n-1個凹槽由4種類型組成,但未有相鄰兩個凹槽高度差為3的。 A2.前n-1個凹槽由4種類型組成,有相鄰兩個凹槽高度差為3的。 B1.前n-1個凹槽由3種類型組成,但未有相鄰兩個凹槽高度差為3的。 B2.前n-1個凹槽由3種類型組成,有相鄰兩個凹槽高度差為3的。 C1.前n-1個凹槽由2種類型組成,但未有相鄰兩個凹槽高度差為3的。 C2.前n-1個凹槽由2種類型組成,有相鄰兩個凹槽高度差為3的。 D. 前n-1個凹槽由1種類型組成。 } 由已知條件“前n-1個凹槽未構成鑰匙,加了第n個凹槽後才符合鑰匙規則” 可以將A2,B2,C2,D的全部情況排除,推得結論n-1個凹槽上必須為4,才符合已知條件。 即:A1+B1+C1=all-(A2+B2+C2+D)=1*4^(n-2)-(one[n-1]+1*2^(n-2)-1+1) 綜合以上兩種情況: one[n]=4^(n-2)-(one[n-1]+2^(n-2))+lock[n-1] two[n]=2^(n-1)-2+lock[n-1] lock[n]=2*(one[n]+two[n]) 參考:https://blog.csdn.net/yuanyunfeng3/article/details/40298903?utm_source=copy

#include<stdio.h>
#include<math.h>
int main()
{
	__int64 one[32]={0},two[32]={0},lock[32]={0};
	one[3]=2;
	lock[2]=0;
	lock[3]=8;
	printf("N=2: 0\n");
	printf("N=3: 8\n");
	for(int n=4;n<32;n++)
	{
	one[n]=(__int64)pow((float)4,n-2)-(__int64)pow((float)2,n-2)-one[n-1]+lock[n-1];
	two[n]=(__int64)pow((float)2,n-1)-2+lock[n-1];
	lock[n]=2*(one[n]+two[n]);
	printf("N=%d: %I64d\n",n,lock[n]);
	}
	getchar();
	return 1;
}