intmain(){ int n; while (cin >> n && n != 0) { int a[10001]; a[0] = 0; for (int i = 1; i <= n; ++i) { cin >> a[i]; }
double b, r, v, e, f; cin >> b >> r >> v >> e >> f;
double cost[10001]; cost[0] = 0; for (int i = 1; i <= a[n]; ++i) { cost[i] = i - 1 < r ? cost[i - 1] + 1 / (v - f * (r - i + 1)) : cost[i - 1] + 1 / (v - e * (i - 1 - r)); }
题号:soj 1828 --Minimal 题目:There are two sets S1 and S2 subjecting to: (1) S1, S2 are both the subsets of {x| x is an integer and 0 < x < 1,000,000} (2) 0 < |S1| < |S2| < 500 F(S1, S2) = min {|a1-b1| + |a2-b2| + … + |aN-bN|} in which ai ∈S1, bi ∈S2, ai ≠aj if i≠j, bi ≠bj if i≠j (i, j = 1, 2 … N,N = |S1|)
For each test case, print the result of F(S1 ,S2).
#define inf 1<<30 constint maxn = 501; int f[maxn][maxn]; int S1[maxn], S2[maxn];
intmain(){ int cases; cin >> cases; while (cases--) { int N, M; cin >> N >> M; for (int i = 1; i <= N; ++i) { cin >> S1[i]; } for (int i = 1; i <= M; ++i) { cin >> S2[i]; }
sort(S1+1, S1+N+1); sort(S2+1, S2+M+1); for (int i = 0; i <= N; ++i) { for (int j = 0; j <= M; ++j) { if (i == 0 && j == 0) f[i][j] = 0; elseif (i > j) { f[i][j] = inf; } else { f[i][j] = inf; if (i > 0) f[i][j] = min(f[i][j], f[i-1][j-1]+abs(S1[i]-S2[j])); if (j > 0) f[i][j] = min(f[i][j], f[i][j-1]); } } } cout << f[N][M] << endl; } }
⭐⭐⭐⭐⭐
Code
1 2
题号:soj 1527 --Tiling a Grid With Dominoes 题目:用1*2的长方形铺满4*n的长方形,有多少种方法?(如下图)
intmain(){ int cases; cin >> cases; for (int i = 1; i <= cases; ++i) { int N; cin >> N; cout << i << " " << dp(N) << endl; } }
⭐⭐⭐⭐⭐
Code
1 2 3 4 5 6 7 8
题号:soj 1148 --过河 题目:在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中 L 是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是 S 到 T 之间的任意正整数(包括S, T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。 给定独木桥的长度 L,青蛙跳跃的距离范围 S、T ,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。
限制: · 1 <= L <= 10^9 · 1 <= S <= T <= 10 · 1 <= M < = 100
用数组 dp[i] 表示走到位置 i 至少需要踩到的石子数,易得 dp[i]=min(dp[i−j])(S<=j<=T)。因为只要青蛙跳到或跳过坐标为L的点时就算已经跳出独木桥,所以最终结果落在[dp[L],dp[L+T−1]]的范围内。 本题更为关键的一点是,L 的范围比较大,直接开长度为 L 的数组几乎不可能,所以要进行状态压缩来达到节省空间的目的。从题目限制来看,S 和 T 比较小,当两个石子之间的距离相对大时,总可以从前一个石子跳到后一个石子,而中间的路程便可以舍去不计。 那么该压缩多少?先从最简单的想起,假如一次只能走 S 或者 T 步,从原点开始走,那么显然一定可以走到LCM(S,T)这个位置。在这种情况下,如果(0, LCM(S,T)]之间没有石子,那么(0,LCM(S,T)]就是无用的,因为它不会对答案产生任何影响,可以把这一段删去。 推广一下就可以知道,从点 i 开始,一次走[S, T]步,一定可以到达 i + LCM(S…T)这个点,利用这个结论,就可以对两点之间的距离进行缩短。 为了免去对 LCM 的计算,直接取100代替 LCM 对距离进行压缩。
int stones[102]; int f[10200] = { 0 }; int dp[10200];
intmain(){ int L, S, T, M; cin >> L >> S >> T >> M; int result = 0; if (S == T) { for (int i = 1; i <= M; ++i) { int temp; cin >> temp; if (temp % S == 0) ++result; } } else { stones[0] = 0; for (int i = 1; i <= M; ++i) { cin >> stones[i]; } sort(stones + 1, stones + M + 1); for (int i = 1; i <= M; ++i) {// 状态压缩 if (stones[i] - stones[i-1] > 99) { int dis = stones[i] - stones[i - 1] - 99; for (int j = i; j <= M; ++j) { stones[j] -= dis; } } f[stones[i]] = 1; } dp[0] = 0;// 走到位置i需要踩到的最小石子数 for (int i = 1; i <= stones[M] + T; ++i) { if (i - S < 0) { dp[i] = -1; continue; } dp[i] = 200; for (int j = S; j <= T; ++j) { if (i - j >= 0 && dp[i - j] != -1) dp[i] = min(dp[i - j], dp[i]); } if (f[i]) ++dp[i]; } result = dp[stones[M]]; for (int i = stones[M] + 1; i <= stones[M] + T; ++i) { result = min(dp[i], result); } } cout << result << endl; return0; }
int f[101][101] = { 0 }; int N; int energy[101][2];
intdp(int start, intend){ if (start == end) return0; if (f[start][end] != 0) return f[start][end]; f[start][end] = 0; if (start < end) { for (int k = start; k < end; ++k) { f[start][end] = max(f[start][end], dp(start, k) + dp(k + 1, end) + energy[start][0] * energy[k][1] * energy[end][1]); } } else { for (int k = start; k <= N; ++k) { f[start][end] = max(f[start][end], dp(start, k) + dp(((k + 1) > N ? k + 1 - N : k + 1), end) + energy[start][0] * energy[k][1] * energy[end][1]); } for (int k = 1; k < end; ++k) { f[start][end] = max(f[start][end], dp(start, k) + dp(k + 1, end) + energy[start][0] * energy[k][1] * energy[end][1]); } } return f[start][end]; }
intmain(){ while (cin >> N) { int pearl[101] = { 0 }; for (int i = 1; i <= N; ++i) { cin >> pearl[i]; } for (int i = 1; i < N; ++i) { energy[i][0] = pearl[i]; energy[i][1] = pearl[i + 1]; } energy[N][0] = pearl[N]; energy[N][1] = pearl[1];
//数组定义在main函数外,每次执行要重置f[][]以覆盖之前的数据,否则出错 for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { f[i][j] = 0; } } f[N][1] = energy[N][0] * energy[1][0] * energy[1][1];
int result = 0; for (int i = 1; i <= N; ++i) { if (i == 1) result = max(result, dp(i, i + N - 1)); else result = max(result, dp(i, (i + N - 1) % N)); } cout << result << endl; } return0; }
当前序列的 i - 1 个数中有 j - 1 个“ < ”: 为使插进数字 i 后 “ < ”数目加一,可以在序列的末尾插入,或者在当前序列的“ > ”的位置插入,此时共有 i - 2 - (j - 1) + 1 = i - j 种选择。
用数组 dp[i][j] 表示长度为 i 且“ < ”个数为 j 的序列的数目,则有递推式:dp[i][j] = dp[i-1][j-1] (i - j) + dp[i-1][j] (j + 1)。 比较巧妙的一个处理是,由于一次测试中可能会有多个测例,而给定的 n 和 k 又比较小,故而把动态规划的过程放在了输入 n, k 的循环体之外来避免存在多个测例时的重复计算。 另外,在main函数中好像不能定义太大的数组,会导致堆栈溢出?总之把它放在main函数外面了。
c++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include<iostream> usingnamespacestd;
int dp[101][101] = { {0} }; intmain(){ int n, k; dp[1][0] = 1; for (int i = 2; i <= 101; ++i) { dp[i][0] = 1; for (int j = 1; j < i; ++j) { dp[i][j] = (dp[i - 1][j - 1] * (i - j) + dp[i - 1][j] * (j + 1)) % 2007; } } while (cin >> n >> k) { cout << dp[n][k] << endl; } return0; }