笨笨的雕塑安置

时间:2021-11-26 04:50:52

笨笨的雕塑安置

    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:容斥原理

S 为有穷集, P 1 P 2 …Pn n 条性质。 S 中的任一元素 x 对于这 n 条性 质可能符合其中的 1 种、 2 种、 n 种,也可能都不符合。设 Ai 表示 S 具有 Pi 性质的元素构成的子集。有限集合 A 中的元素个数记为 |A| 。这时 容斥原理可叙述为: S 中不具有性质 P 1 P 2 …Pn 的元素个数有:
笨笨的雕塑安置
笨笨的雕塑安置