タイトル説明
王は、彼らがそこに配置されているどのように多くのプログラム、お互いを攻撃しないことを、N×Nのチェス盤にKを置きます。王は左にそれを攻撃し、右、左上の8つのグリッドの総数の近傍における各グリッドの右上の右下の8つの方向を左に低下させることができます。
注:データは強化しています(2018年4月25日)
入力形式
二つの数字N、K(1 <= N <= 9、0 <= K <= N * N)を含む唯一のライン、
出力フォーマット
結果の数値プログラム
入力#1
3 2
出力#1
16
問題解決のアイデア:
DPソリューション:
N <言い換える10は、バイナリビットは、次いで、最も1024における状態数を点の状態を示すため、最初、各層内部の法的地位を考えます。彼は連続バイナリビットではありません。1.隣接チェス、攻撃することができますので、
これは状態のすべての法的数を記録するために、直接前処理することができます。状態の数と1の対応する番号。唯一のK個の対象からです。
その後、層の間の関係を検討してください。層によって上下層から検討します。そして、前の層の新たな層は、彼だけに影響を与えることができます。被験者によれば、2つの状態の動作で行うことが0に等しく、かつ、左と右のいずれかまたは0に等しく、法的缶共存あります。その後、状態の層数に新しいレイヤーを追加します。
最後に、トピックがk個を取るように求めているので、中に入れてきた作品の合計数を考慮すべき場所があります。次いで、各DPの値は、個の対応する電流の合計数で記録されるべきです。層を追加する場合、それはまた、STA [ID]ポーンを増加させます。
一見高い3つのサイクルのコードの複雑さは、実際には、とき前の法的地位は、より状態の半分以上を除去するであろう、その複雑さは完全に許容です。
DFSソリューション:
DP溶液と最初のステップは、最初の場合和の場合、すべての法的地位、および数1を前処理し、次いで第一層、シーケンス内の追加層、条件は、最後に列挙第n層同一で列挙K、1が返されます。
DFSのコードはより簡潔が、注意が必要それ以外の場合は、TLEで重複する検索結果の多くになり、メモリの必要性です。場合のメモリ、三つのパラメータが必要とされ、層の数、状態数、及びメモリの断片の合計。簡単な剪定と相まって、あなたACことができます。
ACコード(DP):
#include <bits/stdc++.h>
#define int long long
using namespace std;
int dp[10][100][1024]; // 三维分表代表当前层数,当前放棋子数,当前状态数
int legal[1024]; // 记录合法状态
int id[1024]; // 记录状态数对应的1的个数
signed main()
{
memset(legal,0,sizeof(legal));
memset(id,0,sizeof(id));
int n,m;
cin>>n>>m;
for(int i = 0 ; i < 1024 ; i ++) // 预处理出一层所有的合法状态
{
if(((i<<1)&i) == 0 && ((i>>1)&i) == 0)
legal[i] = 1;
int cnt =0;
for(int j = i ; j != 0 ; j >>= 1)
if(j&1) cnt ++;
if(cnt > m) legal[i] = 0;
else id[i] = cnt;
}
for(int i = 0 ; i < (1<<n) ; i ++)
if(legal[i])
dp[1][id[i]][i] = 1;
for(int i = 2 ; i <= n ;i ++) // 枚举层数
for(int j = 0 ; j < (1<<n) ; j ++) // 枚举本层状态
if(legal[j])
for(int sta = 0; sta < (1<<n) ;sta ++) // 枚举上一层状态
if(legal[sta] && (j&sta) == 0 && ((j<<1)&sta) == 0 && ((j>>1)&sta) == 0 )
for(int k = 0 ; k <= m-id[j] ; k ++)
dp[i][k+id[j]][j] += dp[i-1][k][sta];
int ans = 0;
for(int j = 0 ; j < (1<<n); j ++) // 计算最后方案数总和
ans += dp[n][m][j];
cout<<ans<<endl;
}
ACコード(DP):
#include <bits/stdc++.h>
#define int long long
using namespace std;
int dp[10][100][1024]; // 记忆化数组
int legal[1024]; // 合法状态
int id[1024];
int n,m;
int dfs(int level,int sta,int sum)
{
if(sum > m || level > n) return 0;
if(level == n-1 && sum == m) return 1; // 剪枝
if(dp[level][sum][sta] != -1) return dp[level][sum][sta]; // 已经搜索过的直接返回
int res = 0;
for(int i = 0 ; i < (1<<n) ; i ++) // 枚举第level+1层的状态
{
if(legal[i] && (i&sta) == 0 && ((sta<<1)&i) == 0 && ((sta>>1)&i) == 0)
res += dfs(level+1,i,sum + id[i]);
}
dp[level][sum][sta] = res;
return res;
}
signed main()
{
memset(legal,0,sizeof(legal));
memset(dp,-1,sizeof(dp));
memset(id,0,sizeof(id));
cin>>n>>m;
for(int i = 0 ; i < 1024 ; i ++) // 预处理出一层所有的合法状态
{
if(((i<<1)&i) == 0 && ((i>>1)&i) == 0)
legal[i] = 1;
int cnt = 0;
for(int j = i ; j != 0 ; j >>= 1)
if(j&1) cnt ++;
if(cnt > m) legal[i] = 0;
else id[i] = cnt;
}
int ans = 0;
for(int i = 0 ; i < (1<<n) ; i ++) // 枚举第1层状态
if(legal[i])
ans += dfs(0,i,id[i]);
cout<<ans<<endl;
}