您的位置:首页 > 其它

poj 2779 Mr. Young's Picture Permutations

2013-08-08 09:18 246 查看
浪费我好多时间啊,如果dp实力强的,可以用dp写,确实算是dp的好题,但是我很水,只能去找那个钩子公式,baidu、google都找了,结果只找到英文的原网站(不吐槽,我这种英语水平怎么可能看懂),最后终于看见一篇还可以的,大致的应用会了,大家如果问我证明,我也只能说sorry。

英文原网站:http://en.wikipedia.org/wiki/Young_tableau

题意:杨先生要给他的学生们拍照片,若第i行站了a[i]个人,则有a[1] ≥ a[2] ≥ ... ≥ a
,所有的行都是靠左对齐的。并且,在同一行和同一列里面,从左到右或者从上到下身高都是递减的。现在所有学生的身高都不相同,学生数不超过30个,行数不超过5。你需要求出所有可能的排队方法的总数。

思路:别人说这种问题是钩子公式的模板问题。我来简单的说说钩子公式吧,把学生站队的地方看成一个地图,

最后的总数(sum)为 sum=n! /((H1)*(H2)*....*(Hn)),学生总数为n,对地图上的每个学生进行一个进行一个编号1~n,Hx表示第x个学生同一列(下面的)和同一排(右边的)的学生加上他自己的人数总和,这个编号是对结果无影响的,所以只需要算Hx就ok。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

int gcd(int a,int b)
{
return  a%b==0?b:(gcd(b,a%b)) ;
}

int n,map[14][41],val[51],fact[41],sum;
int main(void)
{
while(cin>>n,n)
{
sum = 0;
memset(map,0,sizeof(map));
for(int i=1;i<=n;++i)
{
int a;
scanf("%d",&a);
sum += a;
for(int j=1;j<=a;++j)
{
map[i][j] = 1;
}
}
int cou = 1;
for(int i=1;i<14;++i)
for(int j=1;j<41;++j)
if(map[i][j])
{
val[cou] = 1;
for(int k=i+1;k<14;++k)
val[cou] += map[k][j];
for(int k=j+1;k<41;++k)
val[cou] += map[i][k];
++cou;
}
for(int i=1;i<=sum;++i)
fact[i] = i;
for(int i=1;i<=sum;++i)
for(int j=1;j<=sum;++j)
{
int tmp = gcd(fact[i],val[j]);
fact[i] /= tmp; val[j] /= tmp;
}
long long num = 1;
for(int i=1;i<=sum;++i)
num *= fact[i];
cout<<num<<endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: