题单链接
显然, d p [ i ] = min ( d p [ i − 1 ] + ∣ h [ i ] − h [ i − 1 ] ∣ , d p [ i − 2 ] + ∣ h [ i ] − h [ i − 2 ] ∣ ) dp[i]=\min(dp[i-1]+|h[i]-h[i-1]|,dp[i-2]+|h[i]-h[i-2]|) dp[i]=min(dp[i−1]+∣h[i]−h[i−1]∣,dp[i−2]+∣h[i]−h[i−2]∣)
ans[2] = abs(h[2] - h[1]);
for (int i = 3; i <= n; ++i)
ans[i] = min(ans[i - 1] + abs(h[i] - h[i - 1]), ans[i - 2] + abs(h[i] - h[i - 2]));
和A差不多,只不过最小值不是从前两个里面取而是由k决定
for (int i = 1; i <= n; ++i)
h[i] = read();
for (int i = 2; i <= n; ++i)
{
ans[i] = INF;
for (int j = 1; j <= k; ++j)
{
if (i > j)
ans[i] = min(ans[i - j] + abs(h[i] - h[i - j]), ans[i]);
}
}
printf("%d", ans[n]);
状态转移方程也比较容易得出:
d p A [ i ] = a [ i ] + max ( d p B [ i − 1 ] , d p C [ i − 1 ] ) dp_A[i]=a[i]+\max(dp_B[i-1],dp_C[i-1]) dpA[i]=a[i]+max(dpB[i−1],dpC[i−1])
d p B [ i ] = b [ i ] + max ( d p A [ i − 1 ] , d p C [ i − 1 ] ) dp_B[i]=b[i]+\max(dp_A[i-1],dp_C[i-1]) dpB[i]=b[i]+max(dpA[i−1],dpC[i−1])
d p C [ i ] = c [ i ] + max ( d p A [ i − 1 ] , d p B [ i − 1 ] ) dp_C[i]=c[i]+\max(dp_A[i-1],dp_B[i-1]) dpC[i]=c[i]+max(dpA[i−1],dpB[i−1])
那么可以得到这样的代码:
for (int i = 1; i <= n; ++i)
{
a[i] = read(), b[i] = read(), c[i] = read();
dp[i][0] = a[i] + max(dp[i-1][2], dp[i-1][1]);
dp[i][1] = b[i] + max(dp[i-1][0], dp[i-1][2]);
dp[i][2] = c[i] + max(dp[i-1][1], dp[i-1][0]);
}
printf("%d\n",max(max(dp[n][0], dp[n][1]), dp[n][2]));
01背包的进化版。
直接做肯定不行,需要按照某种顺序进行排序。
假设在钱足够的情况下有A、B两种东西要买,那么先买A至少需要 p A + q B p_A+q_B pA+qB 的钱,先买B至少需要 p B + q A p_B+q_A pB+qA 的钱,因此如果 q A − p A > q B − p B q_A-p_A>q_B-p_B qA−pA>qB−pB,先买A。但是还需要考虑到, d p [ j ] = max ( d p [ j − p [ i ] ] + v [ i ] , d p [ j ] ) dp[j]=\max(dp[j-p[i]]+v[i],dp[j]) dp[j]=max(dp[j−p[i]]+v[i],dp[j]) 的时候,这个j是最先买的,也就是说在dp的时候选取的商品和其在数组中的顺序是正好相反的,因此排序的时候需要反过来排。
struct merchant
{
int p, q, v;
const bool operator<(const merchant &b) const
{
return q - p < b.q - b.p;
}
} s[509];
int dp[5009];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("data.txt","w",stdout);
//std::ios::sync_with_stdio(false);
//std::cin.tie(0);
int n, m;
while (~scanf("%d%d", &n, &m))
{
memset(dp, 0, sizeof(int)*5009);
for (int i = 1; i <= n; ++i)
scanf("%d%d%d", &s[i].p, &s[i].q, &s[i].v);
sort(s + 1, s + n + 1);
for (int i = 1; i <= n; ++i)
for (int j = m; j >= s[i].q; --j)
dp[j] = max(dp[j], dp[j - s[i].p] + s[i].v);
printf("%d\n", dp[m]);
}
//fclose(stdin);
//fclose(stdout);
return 0;
}
01背包模板题
for (int i = 1; i<= n; ++i)
for (int j = w; j >= p[i]; --j)
dp[j] = max(dp[j], dp[j - p[i]] + v[i]);
巨型背包
这数据范围直接枚举容量一定会T,而N和v都很小,因此求装到某个价值所需要的最小容量,最后降序枚举价值,第一个能装下的就是答案
for (int i = 1; i <= n; ++i)
p[i] = read(), v[i] = read();
for (ull i = 1; i < maxn; ++i)
dp[i] = INF;
for (int i = 1; i <= n; ++i)
for (int j = maxn - 1; j >= v[i]; --j)
dp[j] = min(dp[j], dp[j - v[i]] + p[i]);
for (int i = maxn - 1; i >= 0; --i)
if (dp[i] <= w)
{
cout << i << '\n';
break;
}
这个不知道怎么DP,看起来倒像是拓扑排序,不过还是记忆化搜索写起来比较方便。
vector<int> edge[maxn];
int dis[maxn], ans;
bool vis[maxn];
void dfs(int x)
{
if (vis[x])
return;
vis[x] = true;
for (int i = 0; i < edge[x].size(); ++i)
{
dfs(edge[x][i]);
dis[x] = max(dis[x], dis[edge[x][i]] + 1);
}
ans = max(ans, dis[x]);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("data.txt","w",stdout);
//std::ios::sync_with_stdio(false);
//std::cin.tie(0);
int n = read(), m = read();
while (m--)
{
int x = read(), y = read();
edge[x].emplace_back(y);
}
for (int i = 1; i <= n; ++i)
dfs(i);
cout << ans << '\n';
//fclose(stdin);
//fclose(stdout);
return 0;
}