笨笨的雕塑安置
Wcyz为了迎接百年校庆,美化校园,请了校友笨笨将n座雕塑,准备安置在校园内,整个校园可以抽象成一个nxn的大网格,每个lxl网格最多只能安置一座雕塑,但是某些lxl的网格上恰好是一个食堂或湖泊,这些网格是不能安置雕塑的,每个雕塑的造型相同,这样同一种安置方案中交换排列都算一种。任意雕塑在同一行或同一列是不合法的方案。
学校想知道有多少种安置方案,笨笨想从中选择最好的一种方案,笨笨想请你告诉他方案种数。
【输入格式】
第一行,两个整数n,m(n≤20,m≤10),用空格隔开,n表示nXn的大网格,m表示不能安置雕塑的位置的个数。
第二行至m+l行,每行两个数x,y,用空格分开,表示坐标(x,y)的lxl的网格上不能安置雕塑。
【输出格式】
一个数,方案种数(方案种数≤263_1)
Sample input
6 7
11
21
2 2
3 3
3 4
4 3
4 4
Sample output
184
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int h[100],s[100];
long long d[100],r[100],ans;
int a[100][3],n,m,i,j;
void dfs(int x,int y)
{
if (y==0)
{
r[i]++; return;//r 数组表示排列中有i 处是不能放的方案数
}
for (int j=x+1;j<=m;j++)
if (h[a[j][1]]==0&&s[a[j][2]]==0)
{
h[a[j][1]]=1;
s[a[j][2]]=1;
dfs(j,y-1);
h[a[j][1]]=0;
s[a[j][2]]=0;
}
}
int main()
{
freopen("sculpture.in","r",stdin);
freopen("sculpture.out","w",stdout);
scanf("%d%d",&n,&m);
for (i=1;i<=m;i++)
scanf("%d%d",&a[i][1],&a[i][2]);
for (i=1;i<=m;i++)
dfs(0,i);
d[0]=1;
for (i=1;i<=n;i++)
d[i]=d[i-1]*i;
ans=1;
for (i=1;i<=n;i++)
ans*=i;
for (i=1;i<=m;i++)//这里采用了非常神奇的容斥原理
if (i%2==1)
ans-=r[i]*d[n-i];
else
ans+=r[i]*d[n-i];
cout<<ans;
}
//ps:容斥原理