题目:http://acm.hust.edu.cn/vjudge/contest/129795#problem/Q
题意:
要求从第一层走到最下面一层,只能往左下或右下走,经过的数字之和为Sum。问有多少条路径之和刚好等于Sum? 如果有的话,输出起点编号最小且字典序最小的路径。
分析:
一道类似01背包的题目,Sum相当于是背包容量,状态表示很容易想到:
f[i][j][S]表示从开始走到(i,j)这个位置剩余S的路径数
决策也是显然的:往左还是往右
对应上半段和下半段各自转移相应的状态即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 200 + 9;
int w[44][22], n, Sum, id, cnt;
ll f[44][22][555];
bool vis[44][22][555];
string res;
/*
f[i][j][S]表示从开始走到(i,j)这个位置剩余S的路径数
决策也是显然的:往左还是往右
对应上半段和下半段各自转移相应的状态即可。
*/
ll dfs (int i, int j, int S, string path) {
if (S < 0) return 0;
if (S == 0 && i == n + n) {
if (id == -1) id = cnt, res = path; //第一次到达的一定是编号最小和字典序最小的
return 1;
}
if (i >= n + n) return 0;
if (vis[i][j][S]) return f[i][j][S];
vis[i][j][S] = 1;
ll& ans = f[i][j][S];
if (i < n) { //上半段
if (w[i + 1][j - 1] != -1) ans += dfs (i + 1, j - 1, S - w[i][j], path + 'L');
if (w[i + 1][j] != -1) ans += dfs (i + 1, j, S - w[i][j], path + 'R');
} else { //下半段
if (i + 1 == n + n) ans += dfs (i + 1, j, S - w[i][j], path);
else if (w[i + 1][j] != -1) ans += dfs (i + 1, j, S - w[i][j], path + 'L');
if (w[i + 1][j + 1] != -1) ans += dfs (i + 1, j + 1, S - w[i][j], path + 'R');
}
return ans;
}
int main() {
//freopen ("f.txt", "r", stdin);
while (~scanf ("%d%d", &n, &Sum) && (n + Sum) ) {
memset (w, -1, sizeof (w) );
memset (f, 0, sizeof (f) );
memset (vis, 0, sizeof (vis) );
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n - i + 1; j++)
scanf ("%d", &w[i][j]);
for (int i = n + 1; i < n + n; i++)
for (int j = 1; j <= i - n + 1; j++)
scanf ("%d", &w[i][j]);
id = -1;
ll num = 0;
cnt = 0;
for (int j = 1; j <= n; j++, cnt++) num += dfs (1, j, Sum, "");
printf ("%lld\n", num);
if (num == 0) printf ("\n");
else cout << id << ' ' << res << endl;
}
return 0;
}
/*
SampleInput
5 26
2 8 7 2 5
3 6 0 2
1 3 4
2 5
3
7 2
2 9 3
1 0 4 4
4 8 7 2 3
0 0
SampleOutput
5
2 RLLRRRLR
*/