标签:
HDNOIP201204四个国王 |
难度级别:A; 运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
在N*M的棋盘上摆国际象棋中的“国王”。如果两个“国王”占据的格子有公共边或者公共顶点,那么他们就会相互攻击。现在想知道,一共有多少种不同的方法摆上K个互不攻击的国王呢? |
输入
|
第一行包含三个整数,分别表示N、M和K。
|
输出
|
输出一个整数,表示方法数。若超过2147483647,你只用输出2147483648即可。
|
输入示例
|
样例输入1
3 3 4 样例输入2 5 100 50 |
输出示例
|
样例输出1
1 样例输出2 2147483648 |
其他说明
|
第一个样例只有一种可能:
XOX OOO XOX X表示一个国王,O表示一个空格子。 第二个样例的方法数显然多于2147483647。 对70%的数据,N<=5,M<=5,0<=K<=4, 对另外30%的数据,N<=5,M<=100,0<=K<=N*M |
题解:妈妈呀好题!
"n小思状压,网格用层次",所以很容易得出DP:f[i][j][k]表示前i列放j个国王且第i列状态为a[k]的放法总数
转移:f[i][j][k]=sum(f[i-1][j-b[s_now]][s_think]) (j∈ok_set)
那么肿么求ok_set呢?暴力init就行,如果追求完美可以打表哦~
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<queue> 6 #include<cstring> 7 #define PAU putchar(‘ ‘) 8 #define ENT putchar(‘\n‘) 9 using namespace std; 10 const int maxn=100+10,maxm=500+10,maxs=15,maxt=13,inf=-1u>>1; 11 long long f[maxn][maxm][maxs],sum; 12 int a[maxt]={0,1,2,4,5,8,9,10,16,17,18,20,21},b[maxt]={0,1,1,1,2,1,2,2,1,2,2,2,3},p[6]={0,2,3,5,8,13}; 13 int w[5]={1,2,4,8,16},c,n,m,k;bool g[maxt][maxt]; 14 inline int read(){ 15 int x=0,sig=1;char ch=getchar(); 16 while(!isdigit(ch)){if(ch==‘-‘)sig=-1;ch=getchar();} 17 while(isdigit(ch))x=10*x+ch-‘0‘,ch=getchar(); 18 return x*=sig; 19 } 20 inline void write(int x){ 21 if(x==0){putchar(‘0‘);return;}if(x<0)putchar(‘-‘),x=-x; 22 int len=0,buf[15];while(x)buf[len++]=x%10,x/=10; 23 for(int i=len-1;i>=0;i--)putchar(buf[i]+‘0‘);return; 24 } 25 void init(){ 26 n=read();m=read();k=read(); 27 if(!k||n<=0||m<=0){write(0);return;} 28 for(int i=0;i<p[n]-1;i++) 29 for(int j=i+1;j<p[n];j++){ 30 if(a[i]&a[j]) continue; 31 int d;for(d=0;d<5;d++)if(w[d]&a[i]){ 32 if(d<4&&(w[d+1]&a[j]))break; 33 if(d>0&&(w[d-1]&a[j]))break; 34 }if(d>4)g[i][j]=g[j][i]=true; 35 }g[0][0]=true; 36 for(int i=0;i<p[n];i++)f[1][b[i]][i]=(b[i]<=k); 37 return; 38 } 39 void work(){ 40 for(int i=2;i<=m;i++) 41 for(int j=0;j<=k;j++) 42 for(int c=0;c<p[n];c++) 43 for(int d=0;d<p[n];d++)if(g[c][d]&&j>=b[c]) 44 f[i][j][c]+=f[i-1][j-b[c]][d]; 45 return; 46 } 47 void print(){ 48 for(int j=0;j<p[n];j++){ 49 sum+=f[m][k][j]; 50 if(sum>inf){puts("2147483648");return;} 51 }write(sum); 52 return; 53 } 54 int main(){init();work();print();return 0;}
标签:
原文地址:http://www.cnblogs.com/chxer/p/4637586.html