题意:
求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; }