————传送:洛谷P2530
这道题目还是挺简单的,状态也容易想到。
数据范围非常的小,所以即便是很多维度,复杂度也完全可以接受。定义状态:dp[i][a][b][c]为手上的货物拿到第i个时三种物品分别有a, b, c个所用的最少次数。
状态转移就暴力枚举是放下a,b,c中的哪一个。
只不过需要特判一下n<10的情况。//再一次对自己丑陋的代码有点接受无能……
#include <bits/stdc++.h> using namespace std; #define maxn 102 #define INF 999999 int n, ans = INF, suma[maxn], sumb[maxn], sumc[maxn], dp[maxn][11][11][11]; char c[maxn]; int min(int a, int b) { if(b == -1) return a; if(a == -1) return b; return a < b ? a : b; } int trans(int x, int y, int aa, int bb, int cc) { int a = suma[y] - suma[x], b = sumb[y] - sumb[x], c = sumc[y] - sumc[x]; int sum = a + b + c + aa + bb + cc; bool done = false; if(sum - aa <= 10) done = true, dp[y][a][b + bb][c + cc] = min(dp[x][aa][bb][cc] + 1, dp[y][a][b + bb][c + cc]); if(sum - bb <= 10) done = true, dp[y][a + aa][b][c + cc] = min(dp[x][aa][bb][cc] + 1, dp[y][a + aa][b][c + cc]); if(sum - cc <= 10) done = true, dp[y][a + aa][b + bb][c] = min(dp[x][aa][bb][cc] + 1, dp[y][a + aa][b + bb][c]); if(!done) return -1; else return 0; } int main() { scanf("%d ", &n); memset(dp, -1, sizeof(dp)); for(int i = 1; i <= n; i ++) { cin >> c[i]; suma[i] = suma[i - 1]; sumb[i] = sumb[i - 1]; sumc[i] = sumc[i - 1]; if(c[i] == 'A') suma[i] ++; else if(c[i] == 'B') sumb[i] ++; else sumc[i] ++; } if(n < 10)//特判 { ans = 0; if(suma[n]) ans ++; if(sumb[n]) ans ++; if(sumc[n]) ans ++; printf("%d ", ans); return 0; } dp[10][suma[10]][sumb[10]][sumc[10]] = 0; for(int i = 10; i <= n; i ++) { for(int aa = 0; aa <= 10; aa ++) for(int bb = 0; bb <= 10; bb ++) for(int cc = 0; cc <= 10; cc ++) { if(dp[i][aa][bb][cc] == -1) continue; for(int j = i + 1; j <= n; j ++) if(trans(i, j, aa, bb, cc) == -1) break; } } for(int aa = 0; aa <= 10; aa ++) for(int bb = 0; bb <= 10; bb ++) for(int cc = 0; cc <= 10; cc ++) { if(dp[n][aa][bb][cc] == -1) continue; int tem = 0; if(aa) tem ++; if(bb) tem ++; if(cc) tem ++; ans = min(ans, dp[n][aa][bb][cc] + tem); } printf("%d ", ans); return 0; }