不用看啦,蒟蒻博主没AC,只打了50分的代码!
1:全排列方法暴力判断
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int mod=1e9+7;
bool vis[21];
int a[21],ans;
void dfs(int x,int p,int k)
{
if(x==p+1)
{
ans=(ans+1)%mod;
return;
}
int l,r;
l=max(1,x-k),r=min(p,x+k);
if(a[x]) dfs(x+1,p,k);
else
{
if(x>=3)
if(!vis[x-k])//关键:假设这一位没有用这个数,后面的一定不可能用这个,直接返回就好!
{
vis[max(1,x-k)]=1,dfs(x+1,p,k),vis[max(1,x-k)]=0;
return;
}
for(int i=l;i<=r;i++)
{
if(!vis[i]) vis[i]=1,dfs(x+1,p,k),vis[i]=0;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
ans=0;
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x]=y;
vis[y]=1;
}
if(k==0) ans=1;
else dfs(1,n,k);
printf("%d\n",ans);
}
}
2:状压DP
用一个20位串表示1-n是否用过,枚举每个位置,看可以上面填的数是否用过转移即可
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int mod=1e9+7;
const int maxm=(1<<20)+1;
int dp[maxm],a[21];
int bx[]={-1,0,1,-2,2};
void work1(int n,int t)
{
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=1;i<=n;i++)
{
if(a[i])//此处已有数
{
for(int k=(1<<n)-1;k>=0;k--)
if(!(k&(1<<a[i]-1))) //判断有没有用过a[i]这个数
dp[k|(1<<a[i]-1)]=(dp[k|(1<<a[i]-1)]+dp[k])%mod;//没有向加入a[i]的串中转移方案数
continue;
}
int r;
if(t==1) r=2;
else r=4;
for(int k=(1<<n)-1;k>=0;k--)
for(int j=0;j<=r;j++)
{
int x=i+bx[j];//同上
if(x<1||x>n) continue;//不能越界!
if(!(k&(1<<x-1))) dp[k|(1<<x-1)]=(dp[k|(1<<x-1)]+dp[k])%mod;
}
}
printf("%d\n",dp[(1<<n)-1]);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m,k;
memset(a,0,sizeof(a));
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x]=y;
}
if(k==0) printf("1\n");
else work1(n,k);
}
}