HDU 3811 Permutation 记忆化搜索 状态压缩 DP

题意:

求1-N的排列数但是有限定条件,AI,BI,该排列要满足第AI位为Bi。

算法:

1.裸的DFS

果断TLE。。时间复杂度为N!

View Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
int T, N, M;
int dp[21];
int ans;
int visit[31];

void DFS(int num)
{
   if( num == N + 1 )
   {
      ans++;
      return;   
   }
   for( int i = 1; i <= N; i++)
   {
      if( !visit[i] && (( dp[num] & i) || (dp[num]&(1<<(num-1))) == 0 ) )
      {
          visit[i] = 1;
          DFS( num + 1 );
          visit[i] = 0;     
      }
      
   }
      
}

int main( )
{
  int a,b,Case = 1;
  scanf("%d",&T);
  while( T-- )
  {
    scanf("%d%d",&N,&M);
    memset(visit,0,sizeof(visit));
    memset(dp, 0, sizeof(dp));
    for( int i = 1; i <= M; i++)
    {
       scanf("%d%d",&a,&b);
       dp[a] = dp[a] | (1<<(b-1));
         
    }
    ans = 0;
    DFS( 1 );
    printf("Case %d: %d\n",Case++,ans);
  }  
  return 0;
}

2.记忆化搜索

分析第一种算法可知,如果排列1 2 3. ..15.16的前15为都满足条件,16不满足。。

那么在第一种算法的情况下。程序依然可以枚举1-15阶乘。。浪费了巨大的时间。。

采用记忆化搜索就可避免这种情况发生

int dp[status][2]

dp[status][1]表示该status是合法满足要求的。

dp[status][0]表示改status是不满足要求

初始化值为-1

View Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
int T, N, M;
int use[21][21];
int visit[31];
long long dx[1<<18][2];

long long DFS(int num, int flag, int status)
{
   if( num == N )
   {
      return flag;   
   }
   if( dx[status][flag] != -1 )
      return dx[status][flag];
   long long ret = 0;
   for( int i = 0; i < N; i++)
   {
      if( status & (1<<i) )
          continue;
      if( use[num][i] )
          ret += DFS( num + 1, 1, status | (1<<i));     
      else
          ret += DFS( num + 1, flag, status | (1<<i) );
   }
   return dx[status][flag] = ret;   
}

int main( )
{
  int a,b,Case = 1;
  scanf("%d",&T);
  while( T-- )
  {
    scanf("%d%d",&N,&M);
    memset(use,0,sizeof(use));
    memset(dx,-1,sizeof(dx));
    for( int i = 1; i <= M; i++)
    {
       scanf("%d%d",&a,&b);
       use[a-1][b-1] = 1;
    }
    long long ans;
    ans = DFS(0, 0, 0 );
    printf("Case %d: %I64d\n",Case++,ans);
  }  
  return 0;
}

 

posted on 2012-08-05 11:25  more think, more gains  阅读(169)  评论(0编辑  收藏  举报

导航