【未解之谜】
既然有 f[i+1][j][x+1][max(y-1,0)]+=f[i][j][x][y]
f[i][j+1][max(x-1,0)][y+1]+=f[i][j][x][y]
为什么不能转换成f[i][j][x][y]+=f[i-1][j][x-1][y+1]
f[i][j][x][y]+=f[i][j-1][x+1][y-1]
来求解呢?求助!
【题意】
假设参加party的人中共有n个男孩与m个女孩,就座的方案应满足如下条件:对于任意连续的一段,男孩与女孩的数目之差不超过k。这样的就座方案其实是很多的,由于这个数目可能很多,只要求这个数目除以12345678的余数。
【正解】
DP
设f[i][j][x][y]表示用 i个男生 和 j个女生 组成的座位,男生与女生最大差为x,女生与男生最大差为y时的方案数。
这次DP非常神奇,它不是在求该轮到该值的时候才去搜寻,提前计算好。而它所要做的就是把后面的情况作出它应有的贡献。
所以状态转移方程也十分容易想到了:
①多1个男生的情况:当x+1<=k时,f[i+1][j][x+1][max(y-1,0)]+=f[i][j][x][y]
②多1个女生的情况:当y+1<=k时,f[i][j+1][max(x-1,0)][y+1]+=f[i][j][x][y]
其中式子左边的max(y-1,0)和max(x-1,0)作用一样,防止y-1和x-1取负;
x+1和y+1的原因是因为当男(女)生多了1个,对应的女(男)生就会少1个。
答案为所有男生女生都排上座位后,相差不超过过k的情况和。即Σf[n][m][x][y] (其中x<=k且y<=k)
【解答】
问题1:为什么i和j要从0开始?
解答1:因为上面说了,当前f[i][j][ ][ ]要做的不是更新自己,而是要更新它后面的。所以,尽管我们能直接求出f[i][0][i][0]和f[0][i][0][i]等于1,也不需要将它们初始化了,在计算中自然就求出来了。
问题2:像f[2][3][1][2]意为“2个男生 和 3个女生 组成的座位,男生与女生最大差为1,女生与男生最大差为2时的方案数”,差又是3又是5,结果是不是不存在?
解答2:不是的。如GGBGB就是f[2][3][1][2]的一种方案。
【未解之谜的代码】
既然有 f[i+1][j][x+1][max(y-1,0)]+=f[i][j][x][y]
f[i][j+1][max(x-1,0)][y+1]+=f[i][j][x][y]
为什么不能转换成f[i][j][x][y]+=f[i-1][j][x-1][y+1]
f[i][j][x][y]+=f[i][j-1][x+1][y-1]
来求解呢?求助!
其实,该题的DP方式是“我为人人”,我想看看能不能换成“人人为我”的形式来做。
【题意】
假设参加party的人中共有n个男孩与m个女孩,就座的方案应满足如下条件:对于任意连续的一段,男孩与女孩的数目之差不超过k。这样的就座方案其实是很多的,由于这个数目可能很多,只要求这个数目除以12345678的余数。
【正解】
DP
设f[i][j][x][y]表示用 i个男生 和 j个女生 组成的座位,男生与女生最大差为x,女生与男生最大差为y时的方案数。
这次DP非常神奇,它不是在求该轮到该值的时候才去搜寻,提前计算好。而它所要做的就是把后面的情况作出它应有的贡献。
所以状态转移方程也十分容易想到了:
①多1个男生的情况:当x+1<=k时,f[i+1][j][x+1][max(y-1,0)]+=f[i][j][x][y]
②多1个女生的情况:当y+1<=k时,f[i][j+1][max(x-1,0)][y+1]+=f[i][j][x][y]
其中式子左边的max(y-1,0)和max(x-1,0)作用一样,防止y-1和x-1取负;
x+1和y+1的原因是因为当男(女)生多了1个,对应的女(男)生就会少1个。
答案为所有男生女生都排上座位后,相差不超过过k的情况和。即Σf[n][m][x][y] (其中x<=k且y<=k)
【解答】
问题1:为什么i和j要从0开始?
解答1:因为上面说了,当前f[i][j][ ][ ]要做的不是更新自己,而是要更新它后面的。所以,尽管我们能直接求出f[i][0][i][0]和f[0][i][0][i]等于1,也不需要将它们初始化了,在计算中自然就求出来了。
问题2:像f[2][3][1][2]意为“2个男生 和 3个女生 组成的座位,男生与女生最大差为1,女生与男生最大差为2时的方案数”,差又是3又是5,结果是不是不存在?
解答2:不是的。如GGBGB就是f[2][3][1][2]的一种方案。
【正解代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=12345678;
int f[160][160][30][30];
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
memset(f,0,sizeof(f));
f[0][0][0][0]=1;
for(int i=0;i<=n;i++)//i个男生
{
for(int j=0;j<=m;j++)//j个女生
{
//求f[i][j][ ][ ]
for(int x=0;x<=k;x++)//男-女最大为x
{
for(int y=0;y<=k;y++)//女-男最大为y
{
//求f[i][j][x][y]
if(x+1<=k) f[i+1][j][x+1][max(y-1,0)]=(f[i+1][j][x+1][max(y-1,0)]+f[i][j][x][y])%mod;
if(y+1<=k) f[i][j+1][max(x-1,0)][y+1]=(f[i][j+1][max(x-1,0)][y+1]+f[i][j][x][y])%mod;
}
}
}
}
int ans=0;
for(int x=0;x<=k;x++)
{
for(int y=0;y<=k;y++)
{
ans=(ans+f[n][m][x][y])%mod;
}
}
printf("%d\n",ans);
return 0;
}
【未解之谜的代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=12345678;
int f[160][160][30][30];
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
memset(f,0,sizeof(f));
f[0][0][0][0]=1;
for(int i=1;i<=n;i++) f[i][0][i][0]=1;
for(int i=1;i<=m;i++) f[0][i][0][i]=1;
for(int i=1;i<=n;i++)//i个男生
{
for(int j=1;j<=m;j++)//j个女生
{
//求f[i][j][ ][ ]
for(int x=0;x<=k;x++)//男-女最大为x
{
for(int y=0;y<=k;y++)//女-男最大为y
{
//求f[i][j][x][y]
if(y+1<=k) f[i][j][x][y]=(f[i][j][x][y]+f[i-1][j][x-1][y+1])%mod;
if(x+1<=k) f[i][j][x][y]=(f[i][j][x][y]+f[i][j-1][x+1][y-1])%mod;
}
}
}
}
int ans=0;
for(int x=0;x<=k;x++)
{
for(int y=0;y<=k;y++)
{
ans=(ans+f[n][m][x][y])%mod;
}
}
printf("%d\n",ans);
return 0;
}
推荐:《对动态规划DP的深入理解》http://blog.csdn.net/a_bright_ch/article/details/78880616