bfs + dp 好题。
真好,比赛的时候想不出来,看题解的时候感觉好复杂……
看完写的时候感觉非常流畅!
题意:
载人过岸,一艘船最大载重 k 已经给定。每个人的重量只会是50或者100。问最小的过岸次数与方案数。
思路:
老实说这个题目我可以看就知道是道搜索题,因为和那个什么东西(就是搜索入门的那个)来着非常像。
最重要的还是理清状态与思路。
以左岸50重人数,100重人数,船是否在左岸表示一个状态,对他进行 bfs ,只要满足船重量大于 0 并且小于等于最大 k,每次过岸花费 1 。第一个搜索到 最终状态的就是我们要求的结果。
而我们的方案数,只能通过dp来球,dp最讲求的就是状态,
转移方程如下:
如果是 左岸 — > 右岸 anum表示 50重总人数 , bnum 表示 100重 总人数
( dp[x][y][0] += dp[a][b][1] \times C_a^{a-x} \times C_b^{b-y} )
否则
( dp[x][y][1] += dp[a][b][0] \times C_{anum-a}^{x-a} \times C_{bnum-b}^{y-b} )
写到中间的时候突然发现组合数求不来……尴尬……百度了一下,在数据较小的时候可以直接递推求
( C_n^m = C_n^{m-1} + C_{n-1}^{m-1} )
AC Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 55;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
int n, k;
int anum, bnum, maxa, maxb;
ll dp[maxn][maxn][2], c[maxn][maxn], dis[maxn][maxn][2];
struct status {
int an;
int bn;
int isLeft;
status() {}
status(int _an, int _bn, int _isLeft)
: an(_an)
, bn(_bn)
, isLeft(_isLeft)
{
}
};
queue<status> que;
int bfs()
{
c[0][0] = 1;
for (int i = 1; i <= 50; i++) {
c[i][0] = 1;
for (int j = 1; j <= i; ++j)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
maxa = anum > 0 ? k / anum : 0, maxb = bnum > 0 ? k / bnum : 0;
que.push(status(anum, bnum, 1));
dis[anum][bnum][1] = 0;
dp[anum][bnum][1] = 1;
status now, nxt;
while (!que.empty()) {
now = que.front();
que.pop();
if (!now.an && !now.bn && !now.isLeft)
return dis[0][0][0];
for (int i = 0; i <= maxb; i++)
for (int j = i ? 0 : 1; j <= maxa; j++) {
if (i * 100 + j * 50 > k)
break;
if (now.isLeft) {
if (now.an - j < 0 || now.bn - i < 0)
continue;
nxt.an = now.an - j, nxt.bn = now.bn - i, nxt.isLeft = false;
(dp[nxt.an][nxt.bn][0] += dp[now.an][now.bn][1] * c[now.an][j] % mod * c[now.bn][i] % mod) %= mod;
if (!dis[nxt.an][nxt.bn][0]) {
dis[nxt.an][nxt.bn][0] = dis[now.an][now.bn][1] + 1;
que.push(nxt);
}
} else {
if (now.an + j > anum || now.bn + i > bnum)
continue;
nxt.an = now.an + j, nxt.bn = now.bn + i, nxt.isLeft = true;
(dp[nxt.an][nxt.bn][1] += dp[now.an][now.bn][0] * c[anum - now.an][j] % mod * c[bnum - now.bn][i] % mod) %= mod;
if (!dis[nxt.an][nxt.bn][1]) {
dis[nxt.an][nxt.bn][1] = dis[now.an][now.bn][0] + 1;
que.push(nxt);
}
}
}
}
return -1;
}
int main()
{
int weight;
scanf("%d %d", &n, &k);
for (int i = 0; i < n; i++) {
scanf("%d", &weight);
if (weight == 50)
anum++;
else
bnum++;
}
int step = bfs();
if (step == -1) {
puts("-1\n0");
} else
printf("%d\n%lld\n", step, dp[0][0][0]);
return 0;
}