这道题的思路可能来源于步兵后面必须跟骑兵,反之亦然,那么一个兵种当前的状态肯定是由另一个兵种上一个的状态推来的(即取用该当前取用的兵种之前)。接下来就要考虑怎么控制每次取用多少个人了,由题意可知,每次取用不得超过k1或k2,
我们从1 - n1和从1 - n2表示骑兵和步兵当前的数量表示当前状态,达到当前状态有两种情况,一种情况是上一个状态结尾时骑兵,我们需要去步兵来达到当前状态,另一种情况是上一个状态结尾是步兵,我们需要取骑兵来达到当前状态,这样就形成了基本的递推。我们需要初始化不取用骑兵,取用1 - k1个步兵 和 不取用步兵,取用1 - k2个骑兵,方案数均为1(均可一步到达)。
由于这道题我也没有想明白为什么能想到这样实现,所以没有办法讲明白具体的思路推导,只能说一说自己理解的(bushi
这道题大概有两种实现思路,但思路完全是一样的,我就全放在下面了(个人更喜欢3维的做法,感觉更清晰):
三维
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e8;
void slove()
{
ll n1, n2, k1, k2;
cin >> n1 >> n2 >> k1 >> k2;
ll dp[110][110][3];
//dp[ 使用的步兵数量 ] [ 使用的骑兵数量 ] [ 当前状态结尾是步兵(1)还是骑兵(2) ]
for(ll i = 1; i <= k1; i ++)
{
dp[i][0][1] = 1;
}
for(ll i = 1; i <= k2; i ++)
{
dp[0][i][2] = 1;
}
for(ll i = 1; i <= n1; i ++)
{
for(ll l = 1; l <= n2; l ++)
{
ll num1 = min(i, k1);
ll num2 = min(l, k2);
for(ll op1 = 1; op1 <= num1; op1 ++)
{
dp[i][l][1] += dp[i - op1][l][2];
dp[i][l][1] %= mod;
}
for(ll op2 = 1; op2 <= num2; op2 ++)
{
dp[i][l][2] += dp[i][l - op2][1];
dp[i][l][2] %= mod;
}
}
}
cout << (dp[n1][n2][1] + dp[n1][n2][2]) % mod << endl;
return ;
}
int main()
{
ll t = 1;
// cin >> t;
while(t --){
slove();
}
return 0;
}
四维
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e8;
ll dp[220][3][110][110];
//dp[ 使用的骑兵和步兵数量之和 ] [ 当前状态结尾是步兵(0)还是骑兵(1) ] [ 剩余的步兵数量 ] [ 剩余的骑兵数量 ]
void slove()
{
ll n1, n2, k1, k2;
cin >> n1 >> n2 >> k1 >> k2;
ll r1 = min(k1, n1), r2 = min(k2, n2);
for(ll i = 1; i <= r1; i ++)
{
dp[i][0][n1 - i][n2] = 1;
}
for(ll i = 1; i <= r2; i ++)
{
dp[i][1][n1][n2 - i] = 1;
}
for(ll i = 2; i <= n1 + n2; i ++)
{
for(ll op1 = 0; op1 <= i && op1 <= n1; op1 ++)
{
for(ll op2 = 0; op2 <= i && op2 <= n2; op2 ++)
{
if(op1 + op2 != i)
continue ;
ll num1 = min(op1, k1);
ll num2 = min(op2, k2);
for(ll j = 1; j <= num1; j ++)
{
dp[i][0][n1 - op1][n2 - op2] += dp[i - j][1][n1 - op1 + j][n2 - op2];
dp[i][0][n1 - op1][n2 - op2] %= mod;
}
for(ll j = 1; j <= num2; j ++)
{
dp[i][1][n1 - op1][n2 - op2] += dp[i - j][0][n1 - op1][n2 - op2 + j];
dp[i][1][n1 - op1][n2 - op2] %= mod;
}
}
}
}
// cout << dp[n1 + n2][1][0][0] << " " << dp[n1 + n2][0][0][0] << endl;
cout << (dp[n1 + n2][1][0][0] + dp[n1 + n2][0][0][0]) % mod << endl;
}
int main()
{
ll t = 1;
// cin >> t;
while(t --)
{
slove();
}
return 0;
}
这题是变形的背包题,个人感觉这题可能直接暴力搜索可能会简单很多,但毕竟再练dp就一直在想dp思路,假了一版思路之后就去研究题解的做法了,看题解之前没有啥思路,但看了之后感觉理所当然的就应该那样做。。。还是要多练啊,现在看dp没之前那么困难了