动态规划

数字三角形模型

最低通行费

#include <bits/stdc++.h>
using namespace std;
const int N = 105, inf = 0x3f3f3f3f;
int dp[N][N], a[N][N], r, c, T;
int main()
{

	scanf("%d", &r);
	c = r;
	for (int i = 1; i <= r; ++ i)
	{
		for (int j = 1; j <= c; ++ j) scanf("%d", &a[i][j]);
	}
	memset(dp, 0x3f, sizeof dp);
	dp[0][1] = dp[1][0] = 0;
	for (int i = 1; i <= r; ++ i)
	{
		for (int j = 1; j <= c; ++ j)
		{
			dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + a[i][j];
		}
	}
	printf("%d\n", dp[r][c]);
	return 0;
}

方格取数

#include <bits/stdc++.h>
using namespace std;
const int N = 12;
int n, dp[N + N][N][N];
int a[N][N];
int main()
{
	scanf("%d", &n);
	while(true)
	{
		int x, y, w;
		scanf("%d %d %d", &x, &y, &w);
		if(!x && !y && !w) break;
		a[x][y] = w;
	}
	for (int k = 2; k <= n + n; ++ k)
	{
		for (int i1 = max(1, k - n); i1 <= n && i1 <= k - 1; ++ i1)
		{
			
			for (int i2 = max(1, k - n); i2 <= n && i2 <= k - 1; ++ i2)
			{
				if(i1 == i2)
				{
					dp[k][i1][i2] = max(dp[k - 1][i1][i2], max(dp[k - 1][i1][i2 - 1], max(dp[k - 1][i1 - 1][i2], dp[k - 1][i1 - 1][i2 - 1]))) + a[i1][k - i1];
				}
				else
				{
					dp[k][i1][i2] = max(dp[k - 1][i1][i2], max(dp[k - 1][i1][i2 - 1], max(dp[k - 1][i1 - 1][i2], dp[k - 1][i1 - 1][i2 - 1]))) + a[i1][k - i1] + a[i2][k - i2];
				}
			}
		}
	}
	printf("%d", dp[n + n][n][n]);
	return 0;
}

传纸条

#include <bits/stdc++.h>
using namespace std;
const int N = 52, inf = 0x3f3f3f3f;
int n, dp[N + N][N][N], m;
int a[N][N];
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++ i)
	{
		for (int j = 1; j <= m; ++ j) scanf("%d", &a[i][j]);
	}
	for (int k = 2; k <= n + m; ++ k)
	{
		for (int i1 = max(1, k - m); i1 <= n && i1 <= k - 1; ++ i1)
		{
			
			for (int i2 = max(1, k - m); i2 <= n && i2 <= k - 1; ++ i2)
			{
				if(i1 != i2 || k == 2 || k == n + m)
				{
					dp[k][i1][i2] = max(dp[k - 1][i1 - 1][i2 - 1], max(dp[k - 1][i1][i2], max(dp[k - 1][i1][i2 - 1], dp[k - 1][i1 - 1][i2]))) + a[i1][k - i1] + a[i2][k - i2];
				}
				else dp[k][i1][i2] = -inf;
			}
		}
	}
	printf("%d", dp[n + m][n][n]);
	return 0;
}

最长上升子序列

怪盗基德的滑翔翼

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int T, dp[N], h[N], a[N];
int main()
{
	scanf("%d", &T);
	while(T --)
	{
		int n;
		scanf("%d", &n);
		for (int i = 1; i <= n; ++ i) dp[i] = 0, scanf("%d", &h[i]);
		int ans = 0;
		for (int i = 1; i <= n; ++ i) 
		{
			dp[i] = 1;
			for (int j = 1; j <= i - 1; ++ j)
			{
				if(h[i] < h[j]) dp[i] = max(dp[i], dp[j] + 1); 
			}
			ans = max(ans, dp[i]);
		}
		for (int i = 1; i <= n; ++ i) dp[i] = 0;
		for (int i = 1; i <= n; ++ i) a[i] = h[n - i + 1];
		for (int i = 1; i <= n; ++ i)
		{
			dp[i] = 1;
			for (int j = 1; j <= i - 1; ++ j)
			{
				if(a[i] < a[j]) dp[i] = max(dp[i], dp[j] + 1);
			}
			ans = max(ans, dp[i]);
		}
		printf("%d\n", ans);
	}
	return 0;
}

登山

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dp1[N], a[N], dp2[N], n;
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]), dp1[i] = 1, dp2[i] = 1;
	for (int i = 1; i <= n; ++ i)
	{
		for (int j = 1; j <= i - 1; ++ j)
		{
			if(a[i] > a[j]) dp1[i] = max(dp1[i], dp1[j] + 1);
		}
	}
	for (int i = n; i >= 1; -- i)
	{
		for (int j = n; j >= i + 1; -- j)
		{
			if(a[i] > a[j]) dp2[i] = max(dp2[i], dp2[j] + 1);
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; ++ i)
	{
		ans = max(ans, dp1[i] + dp2[i] - 1);
	}
	printf("%d", ans);
}

合唱队形

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dp1[N], a[N], dp2[N], n;
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]), dp1[i] = 1, dp2[i] = 1;
	for (int i = 1; i <= n; ++ i)
	{
		for (int j = 1; j <= i - 1; ++ j)
		{
			if(a[i] > a[j]) dp1[i] = max(dp1[i], dp1[j] + 1);
		}
	}
	for (int i = n; i >= 1; -- i)
	{
		for (int j = n; j >= i + 1; -- j)
		{
			if(a[i] > a[j]) dp2[i] = max(dp2[i], dp2[j] + 1);
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; ++ i)
	{
		ans = max(ans, dp1[i] + dp2[i] - 1);
	}
	printf("%d", n - ans);
}

友好城市

#include <bits/stdc++.h>
using namespace std;
const int N = 1000005;
#define x first
#define y second
pair<int, int> p[N];
int n, dp[N], ans = 0, bit[N], tot;
int lowbit(int &x)
{
	return x & (-x);
}
void update(int x, int k)
{
	for (int i = x; i <= tot; i += lowbit(i)) bit[i] = max(bit[i], k);
	return ;
}
int query(int x)
{
	int ans = 0;
	for (int i = x; i >= 1; i -= lowbit(i)) ans = max(ans, bit[i]);
	return ans;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) scanf("%d %d", &p[i].first, &p[i].second), tot = max(tot, p[i].y);
	sort(p + 1, p + n + 1);
	tot = max(tot, p[1].x);
	for (int i = 1; i <= n; ++ i)
	{
		dp[i] = query(p[i].y) + 1;
		update(p[i].y, dp[i]);
		ans = max(ans, dp[i]);
	}
	printf("%d", ans);
	return 0;
}

最大上升子序列和

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, a[N], dp[N], ans = 0;

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	for (int i = 1; i <= n; ++ i) 
	{
		dp[i] = a[i];
		for (int j = 1; j <= i - 1; ++ j) 
		{
			if(a[j] < a[i] && dp[i] < dp[j] + a[i]) dp[i] = dp[j] + a[i];
		}
		ans = max(ans, dp[i]);
	}
	printf("%d", ans);
	return 0;
}

拦截导弹

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int b[N], dp[N], bit[N], a[N];
int tot = 0, n;
int lowbit(int i)
{
	return i & (-i);
}
void update(int x, int k)
{
	for (int i = x; i <= n; i += lowbit(i)) bit[i] = max(bit[i], k);
	return ;
}
int query(int x)
{
	int ans = 0;
	for (int i = x; i >= 1; i -= lowbit(i)) ans = max(ans, bit[i]);
	return ans; 
}
int main()
{
	while(scanf("%d", &a[n + 1]) != EOF) { n ++;}
	for (int i = 1; i <= n; ++ i) b[i] = a[i];
	sort(b + 1, b + n + 1);
	tot = unique(b + 1, b + n + 1) - b - 1;
	int ans = 0;
	for (int i = 1; i <= n; ++ i)
	{
		a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
		a[i] = n - a[i] + 1;
	}
 	for (int i = 1; i <= n; ++ i)
	{
		dp[i] = query(a[i]) + 1;
		update(a[i], dp[i]);
		ans = max(ans, dp[i]);
		a[i] = n - a[i] + 1;
	}
	tot = 1, b[1] = a[1];
 	for (int i = 2; i <= n; ++ i)
	{
		if(a[i] > b[tot]) b[++ tot] = a[i];
		else
		{
			int l = 0, r = tot, mid, pos = 0;
			while(l <= r)
			{
				mid = (l + r) >> 1;
				if(a[i] <= b[mid]) r = mid - 1, pos = mid;
				else l = mid + 1;
			}
			b[pos] = a[i];
		} 
	}
	printf("%d\n%d", ans, tot);
}

导弹防御系统

#include <bits/stdc++.h>
using namespace std;
const int N = 55;
int a[N], u[N], d[N], ans, n;
void dfs(int x, int su, int sd)
{
	if(su + sd >= ans) return ;
	if(x == n + 1)
	{
		ans = su + sd;
		return ;
	}
	int pos = su + 1;
	for (int i = 1; i <= su; ++ i)
	{
		if(a[x] >= u[i]) {pos = i; break; }
	}
	int t = u[pos];
	u[pos] = a[x];
	if(pos == su + 1) dfs(x + 1, su + 1, sd);
	else dfs(x + 1, su, sd);
	u[pos] = t;
	
	pos = sd + 1;
	for (int i = 1; i <= sd; ++ i)
	{
		if(a[x] <= d[i]) {pos = i; break; }
	}
	t = d[pos];
	d[pos] = a[x];
	if(pos == sd + 1) dfs(x + 1, su, sd + 1);
	else dfs(x + 1, su, sd);
	d[pos] = t;
	return ;
}
int main()
{
	while(scanf("%d", &n) != EOF)
	{
		if(n == 0) break;
		for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
		ans = n;
		dfs(1, 0, 0);
		printf("%d\n", ans);
	}
	return 0;
}

最长公共上升子序列

#include <bits/stdc++.h>
using namespace std;
const int N = 3005;
int n, dp[N][N], maxv = 0;
int a[N], b[N];
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	for (int i = 1; i <= n; ++ i) scanf("%d", &b[i]);
	for (int i = 1; i <= n; ++ i)
	{
		maxv = 0;
		for (int j = 1; j <= n; ++ j)
		{
			dp[i][j] = dp[i - 1][j];
			if(a[i] == b[j])
			{
				dp[i][j] = max(1, maxv + 1);
//				for (int k = 1; k <= j - 1; ++ k)
//				{
//					if(b[k] < b[j]) dp[i][j] = max(dp[i][j], dp[i - 1][k] + 1); 
//				}
			}
			if(b[j] < a[i]) maxv = max(maxv, dp[i][j]);
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; ++ i) ans = max(ans, dp[n][i]);  
	printf("%d", ans);
	return 0;
}

背包模型

采药(01背包)

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dp[N], T, m, t, w;
int main()
{
	scanf("%d %d", &T, &m);
	for (int i = 1; i <= m; ++ i)
	{
		scanf("%d %d", &t, &w);
		for (int j = T; j >= w; -- j)
		{
			dp[j] = max(dp[j], dp[j - t] + w);
		}
	}
	printf("%d", dp[T]);
	return 0;
}

装箱问题(01背包)

#include <bits/stdc++.h>
using namespace std;
const int N = 20005;
int dp[N], T, m, t, w;
int main()
{
	scanf("%d %d", &T, &m);
	for (int i = 1; i <= m; ++ i)
	{
		scanf("%d", &t);
		w = t;
		for (int j = T; j >= w; -- j)
		{
			dp[j] = max(dp[j], dp[j - t] + w);
		}
	}
	printf("%d", T - dp[T]);
	return 0;
}

宠物小精灵之收服

#include <bits/stdc++.h>
using namespace std;
int dp[1005][505];
int n, m, k;
int main()
{
	scanf("%d %d %d", &n, &m, &k);
	for (int i = 1; i <= k; ++ i)
	{
		int g, e;
		scanf("%d %d", &g, &e);
		for (int x = n; x >= g; -- x)
		{
			for (int y = m; y >= e; -- y)
			{
				dp[x][y] = max(dp[x][y], dp[x - g][y - e] + 1);
			}
		}
	}
	int val;
	if(dp[n][m] == dp[n][m - 1]) val = dp[n][m];
	else val = dp[n][m - 1];
	for (int y = 0; y <= m; ++ y)
	{
		if(val == dp[n][y]) 
		{
			printf("%d %d", val, m - y);
			break;
		}
	}	
	return 0;
}

数字组合

#include <bits/stdc++.h>
using namespace std;
int dp[10005], n, m;
int main()
{
	scanf("%d %d", &n, &m);
	dp[0] = 1;
	for (int i = 1; i <= n; ++ i)
	{
		int w;
		scanf("%d", &w);
		for (int j = m; j >= w; -- j) dp[j] += dp[j - w];
	}
	printf("%d", dp[m]);
	return 0;
}

买书

#include <bits/stdc++.h>
using namespace std;
int dp[10005], m, w[5];
int main()
{
	scanf("%d", &m);
	dp[0] = 1;
	w[1] = 10, w[2] = 20, w[3] = 50, w[4] = 100;
	for (int i = 1; i <= 4; ++ i)
	{
		for (int j = w[i]; j <= m; ++ j) dp[j] += dp[j - w[i]];
	}
	printf("%d", dp[m]);
	return 0;
}

货币系统

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m;
ll dp[3005];
int main()
{
	scanf("%d %d", &n, &m);
	dp[0] = 1ll;
	for (int i = 1; i <= n; ++ i)
	{
		int w;
		scanf("%d", &w);
		for (int j = w; j <= m; ++ j) dp[j] += dp[j - w];
	}
	printf("%lld", dp[m]);
	return 0;
}

货币系统

#include <bits/stdc++.h>
using namespace std;
const int N = 25005;
int dp[N], a[N], n, T;
int main()
{
	dp[0] = 1;
	scanf("%d", &T);
	while(T --)
	{
		scanf("%d", &n);
		int tot = 0;
		for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]), tot = max(tot, a[i]);
		for (int i = 1; i <= tot; ++ i) dp[i] = 0;
		for (int i = 1; i <= n; ++ i)
		{
			for (int j = a[i]; j <= tot; ++ j) dp[j] += dp[j - a[i]];
		}
		int m = 0;
		for (int i = 1; i <= n; ++ i) if(dp[a[i]] == 1) m ++;
		printf("%d\n", m); 
	}
	return 0;
}

多重背包问题 III

#include <bits/stdc++.h>
using namespace std;
const int N = 20005;
typedef long long ll;
ll dp[2][N], w;
int n, v, s, V, hh = 0, q[N], tt = 0;

int main()
{
	scanf("%d %d", &n, &V);
	for (int i = 1; i <= n; ++ i)
	{
		scanf("%d %lld %d", &v, &w, &s);
		for (int k = 0; k < v; ++ k)
		{
			tt = 1, hh = 0;
			for (int j = k; j <= V; j += v)
			{
				while(tt <= hh && j - q[tt] > s * v) tt ++;
				while(tt <= hh && dp[(i & 1) ^ 1][j] >= dp[(i & 1) ^ 1][q[hh]] + (j - q[hh]) / v * w) hh --;
				q[++ hh] = j;
				dp[i & 1][j] = dp[(i & 1) ^ 1][q[tt]] + (j - q[tt]) / v * w;
			}
		}
	}
	printf("%lld", dp[n & 1][V]);
	return 0;
}

庆功会

#include <bits/stdc++.h>
using namespace std;
const int M = 6005;
int dp[2][M], n, m, tt, hh, stk[M];
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++ i)
	{
		int v, w, s;
		scanf("%d %d %d", &v, &w, &s);
		for (int j = 0; j <= v - 1; ++ j)
		{
//			for (int k = 0; k <= s; ++ k)
//			{
//				if(j - k * v >= 0) dp[j] = max(dp[j], dp[j - k * v] + k * w);				
//			}
			tt = 1, hh = 0;
			for (int k = j; k <= m; k += v) 
			{
				while(tt <= hh && k - stk[tt] > s * v) tt ++;
				while(tt <= hh && dp[i & 1][k] >= (k - stk[hh]) / v * w + dp[i & 1][stk[hh]]) hh --;
				stk[++ hh] = k;
				dp[(i & 1) ^ 1][k] = dp[i & 1][stk[tt]] + (k - stk[tt]) / v * w;
			}
		}
	}
	printf("%d", dp[(n & 1) ^ 1][m]);
}

混合背包问题

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dp[2][N], n, V, q[N];
int main()
{
	scanf("%d %d", &n, &V);
	for (int i = 1; i <= n; ++ i)
	{
		int v, w, s;
		scanf("%d %d %d", &v, &w, &s);
		if(s == -1)
		{
			for (int j = V; j >= v; -- j) 
			{
				dp[i & 1][j] = max(dp[i & 1][j], dp[i & 1 ^ 1][j - v] + w);
			}
			for (int j = v - 1; j >= 0; -- j) dp[i & 1][j] = dp[i & 1 ^ 1][j];
		}
		else if(s == 0)
		{
			for (int j = 0; j <= v - 1; ++ j) dp[i & 1][j] = dp[i & 1 ^ 1][j];
			for (int j = v; j <= V; ++ j) 
			{
				dp[i & 1][j] = dp[i & 1 ^ 1][j];
				dp[i & 1][j] = max(dp[i & 1][j], dp[i & 1][j - v] + w);
			}
		}
		else
		{
			for (int j = 0; j < v; ++ j)
			{
				int tt = 1, hh = 0;
				for (int k = j; k <= V; k += v)
				{
					while(tt <= hh && k - q[tt] > s * v) tt ++;
					while(tt <= hh && dp[i & 1 ^ 1][k] >= dp[i & 1 ^ 1][q[hh]] + (k - q[hh]) / v * w) hh --;
					q[++ hh] = k;
					dp[i & 1][k] = dp[i & 1 ^ 1][q[tt]] + (k - q[tt]) / v * w; 
				}
			}
		}
	}
	printf("%d", dp[n & 1][V]);
	return 0;
}

二维费用的背包问题

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int dp[N][N], n, V, M;
int main()
{
	scanf("%d %d %d", &n, &V, &M);
	for (int i = 1; i <= n; ++ i)
	{
		int v, m, w;
		scanf("%d %d %d", &v, &m, &w);
		for (int j = V; j >= v; -- j)
		{
			for (int k = M; k >= m; -- k)
			{
				dp[j][k] = max(dp[j][k], dp[j - v][k - m] + w);		
			}
		}	
	}		
	printf("%d", dp[V][M]);
}

潜水员

#include <bits/stdc++.h>
using namespace std;
const int N = 305;
int n, m, k, dp[N][N];
int main()
{
	scanf("%d %d %d", &n, &m, &k);
	memset(dp, 0x3f, sizeof(dp));
	dp[0][0] = 0;
	for (int i = 1; i <= k; ++ i)
	{
		int a, b, c;
		scanf("%d %d %d", &a, &b, &c);
		for (int x = n; x >= 0; -- x)
		{
			for (int y = m; y >= 0; -- y)
			{
				dp[x][y] = min(dp[x][y], dp[max(0, x - a)][max(0, y - b)] + c);
			}
		}
	}
	printf("%d", dp[n][m]);
	return 0;
}

机器分配

#include <bits/stdc++.h>
using namespace std;
const int N = 15, M = 20;
int n, m, dp[N][M], f[N][M], val[N][M];
void dfs(int x, int y)
{
	if(x == 0) return ;
	printf("%d %d\n", x, f[x][y]);
	dfs(x - 1, y - f[x][y]);
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++ i)
	{
		for (int j = 1; j <= m; ++ j)
		{
			int w;
			scanf("%d", &w);
			for (int k = j; k <= m; ++ k)
			{
				if(k - j >= 0 && dp[i][k] < dp[i - 1][k - j] + w)
				{
					dp[i][k] = dp[i - 1][k - j] + w;
					f[i][k] = j;
				}
				if(dp[i][k] < dp[i - 1][k]) dp[i][k] = dp[i - 1][k], f[i][k] = 0;
			}
			val[i][j] = w;
		}
	}
	printf("%d\n", dp[n][m]);
	dfs(n, m);
}

开心的金明

#include <bits/stdc++.h>
using namespace std;
const int N = 30005;
int n, dp[N], m;
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= m; ++ i)
	{
		int v, w;
		scanf("%d %d", &v, &w);
		for (int j = n; j >= v; -- j) dp[j] = max(dp[j], dp[j - v] + v * w);
	}
	printf("%d", dp[n]);
	return 0;
}

有依赖的背包问题

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n, dp[N][N], m, rt, v[N], w[N];
vector<int> g[N];
void dfs(int x)
{
	for (int i = v[x]; i <= m; ++ i) dp[x][i] = w[x];
	for (int i = 0; i < g[x].size(); ++ i)
	{
		int y = g[x][i];
		dfs(y);
		for (int j = m; j >= v[x]; -- j)//这是x的总情况 
		{
			for (int k = 0; k <= j - v[x]; ++ k) 
			{
				dp[x][j] = max(dp[x][j], dp[y][k] + dp[x][j - k]);
			}
		}
	}
	return ;
}
int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; ++ i)
	{
		int p;
		scanf("%d %d %d", &v[i], &w[i], &p);
		if(p == -1) rt = i;
		else g[p].push_back(i);
	}
	dfs(rt);
	printf("%d", dp[rt][m]);
	return 0;
}

背包问题求方案数

#include <bits/stdc++.h>
using namespace std;
const int N = 1005, mod = 1000000000 + 7;
int n, V, v[N], w[N], dp[N], f[N];
int main()
{
	scanf("%d %d", &n, &V);
	memset(dp, -0x3f, sizeof(dp));
	f[0] = 1, dp[0] = 0;
	for (int i = 1; i <= n; ++ i)
	{
		scanf("%d %d", &v[i], &w[i]);
		for (int j = V; j >= v[i]; -- j)
		{
			if(dp[j] < dp[j - v[i]] + w[i]) dp[j] = dp[j - v[i]] + w[i], f[j] = f[j - v[i]];
			else if(dp[j] == dp[j - v[i]] + w[i]) f[j] = (f[j] + f[j - v[i]]) % mod;
		}
	}
	int mx = -0x3f3f3f3f, sum = 0;
	for (int j = V; j >= 0; -- j) mx = max(mx, dp[j]);
	for (int j = V; j >= 0; -- j)
	{
		if(dp[j] == mx) sum = (sum + f[j]) % mod;
	}
	printf("%d", sum);
	return 0;
}

背包问题求具体方案

#include <bits/stdc++.h>
using namespace std;
const int N = 1005, mod = 1000000000 + 7;
int n, V, v[N], w[N], dp[N][N], f[N][N];
void dfs(int now, int x)
{
	if(!now) return ;
	if(f[now][x]) printf("%d ", f[now][x]);
	dfs(now - 1, x - v[f[now][x]]);
}
int main()
{
	scanf("%d %d", &n, &V);
	for (int i = 1; i <= n; ++ i)
	{
		scanf("%d %d", &v[i], &w[i]);
	}
	
	for (int i = 1; i <= n; ++ i)
	{
		int x = n - i + 1;
		for (int j = 0; j <= V; ++ j) dp[i][j] = dp[i - 1][j];
		for (int j = v[x]; j <= V; ++ j)
		{
			if(dp[i][j] <= dp[i - 1][j - v[x]] + w[x]) 
			{
				dp[i][j] = dp[i - 1][j - v[x]] + w[x];
				f[i][j] = x;
			}
		}
	}
	dfs(n, V);
	return 0;
}

能量石

#include <bits/stdc++.h>
using namespace std;
const int N = 10005;
int T, n, dp[N], sum = 0;
struct node
{
	int s, e, l;
	friend bool operator < (node a, node b)
	{
		return 1.0 * a.s / a.l < 1.0 * b.s / b.l;
	}
}p[N];
int main()
{
	scanf("%d", &T);
	for (int t = 1; t <= T; ++ t)
	{
		scanf("%d", &n);
		sum = 0;
		for (int i = 1; i <= n; ++ i)
		{
			scanf("%d %d %d", &p[i].s, &p[i].e, &p[i].l);
			sum += p[i].s;
		}
		sort(p + 1, p + n + 1);
		for (int i = 0; i <= sum; ++ i) dp[i] = 0;
		for (int i = 1; i <= n; ++ i)
		{
			for (int j = sum; j >= p[i].s; -- j)
			{
				dp[j] = max(dp[j], dp[j - p[i].s] + max(0, p[i].e - p[i].l * (j - p[i].s)));
			}
		}
		int ans = 0;
		for (int i = 0; i <= sum; ++ i) ans = max(ans, dp[i]);
		printf("Case #%d: %d\n", t, ans);
	}
	return 0;
}

金明的预算方案

不是正解。、。。

#include <bits/stdc++.h>
using namespace std;
const int N = 40005;
int dp[65][N], m, n, rt, v[N], w[N];
vector<int> g[N];
void dfs(int x)
{
	for (int i = v[x]; i <= m; i ++) dp[x][i] = v[x] * w[x];
	for (int i = 0; i < g[x].size(); ++ i)
	{
		int y = g[x][i];
		dfs(y);
		for (int j = m; j >= v[x]; -- j)
		{
			for (int k = 0; k <= j - v[x]; ++ k) dp[x][j] = max(dp[x][j], dp[y][k] + dp[x][j - k]);
		}
	}
	return ;
}
int main()
{
	scanf("%d %d", &m, &n);
	bool pd = true;
	for (int i = 1; i <= n; ++ i)
	{
		int p;
		scanf("%d %d %d", &v[i], &w[i], &p);
		if(v[i] % 100) pd = false;
		if(p == 0) g[0].push_back(i);
		else g[p].push_back(i);
	}
	if(pd == false)
	{
		for (int i = 1; i <= n; ++ i) v[i] = v[i] / 10;
		m = (m - m % 10) / 10; 
		dfs(0);
		printf("%d", dp[0][m] * 10);
	}
	else
	{
		for(int i = 1; i <= n; ++ i) v[i] = v[i] / 100;
		m = (m - m % 100) / 100;
		dfs(0);
		printf("%d", dp[0][m] * 100);
	}
} 

状态机模型

大盗阿福

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, dp[N][2], T;
int main()
{
	scanf("%d", &T);
	while(T --)
	{
		scanf("%d", &n);
		for (int i = 0; i <= n; ++ i) dp[i][0] = dp[i][1] = 0;
		for (int i = 1; i <= n; ++ i)
		{
			int x;
			scanf("%d", &x);
			dp[i][1] = max(dp[i - 1][0] + x, dp[i - 1][1]);
			dp[i][0] = max(dp[i - 1][1], dp[i - 1][0]);
		}
		printf("%d\n", max(dp[n][0], dp[n][1]));
	}
	return 0;
}

股票买卖 IV

#include <bits/stdc++.h>
using namespace std;
const int N = 100001;
int n, dp[N][102], K, a[N];
int tt = 1, hh = 0, q[N];
int main()
{
	scanf("%d %d", &n, &K);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	for (int k = 1; k <= K; ++ k)
	{
		tt = 1, hh = 0;
		for (int i = 1; i <= n; ++ i)
		{
			dp[i][k] = max(dp[i][k - 1], dp[i - 1][k]);
			if(tt <= hh) dp[i][k] = max(dp[i][k], dp[q[tt]][k - 1] + a[i] - a[q[tt] + 1]);	
			while(tt <= hh && q[tt] > i - 2) tt ++;
			while(tt <= hh && dp[q[hh]][k - 1] - a[q[hh] + 1] < dp[i - 1][k - 1] - a[i - 1 + 1]) hh --;
			q[++ hh] = i - 1;
//			for (int j = 0; j <= i - 2; ++ j)
//			{
//				dp[i][k] = max(dp[i][k], dp[j][k - 1] + a[i] - a[j + 1]);
//			}
		}
	}
	printf("%d", dp[n][K]);
	return 0;
}

股票买卖 V

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, dp[N][2], a[N]; 
int q[N], cnt = 0;
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	for (int i = 1; i <= n; ++ i)
	{
		dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);
		if(cnt) dp[i][1] = max(dp[i][1], dp[q[1]][0] + a[i] - a[q[1] + 1]);
		while(cnt && dp[q[cnt]][0] - a[q[cnt] + 1] < dp[i - 1][0] - a[i - 1 + 1]) cnt --;
		q[++ cnt] = i - 1;
//		for (int j = 0; j <= i - 2; ++ j)
//		{
//			dp[i][1] = max(dp[i][1], dp[j][0] + a[i] - a[j + 1]);
//		}
	}
	printf("%d", max(dp[n][0], dp[n][1]));
	return 0;
}
/*
如果我今天要买入股票,那么我的昨天一定不能卖股票
1代表这一条卖出股票,0代表一天没有卖出股票 
*/

设计密码

kmp中的\(next\)数组:\(next[i]\)表示该字符串中\([1, next[i]]\)\([i - next[i] + 1, i]\)中方的字符串是相同的。

所以匹配子串发现i + 1位置不符合的时候,即前面\([1,i]\)是符合的,只需要用\(next[i] + 1\)的位置和\(i + 1\)再试一遍就可以了。

dp的时候暴力尝试路径,用kmp批判,判断是不是子串就可以了

\(dp[i][j]\)表示在第\(i\)个空位时,前面已经有\(j\)个字母和T相同的方案数

#include <bits/stdc++.h>
using namespace std;
const int N = 55;
int n, dp[N][N],  m, nxt[N];
char s[N];
const int mod = 1000000007;
int main()
{
	scanf("%d", &n);
	scanf("%s", s + 1);
	m = strlen(s + 1);
	dp[0][0] = 1;
	for (int i = 0, j = 2; j <= n; ++ j)
	{
		while(i && s[i + 1] != s[j]) i = nxt[i];
		if(s[i + 1] == s[j]) i ++;
		nxt[j] = i;
	}
	for (int i = 1; i <= n; ++ i)
	{
		for (int j = 0; j <= m - 1; ++ j)
		{
			for (int c = 'a'; c <= 'z'; ++ c)
			{
				int u = j;
				while(u && s[u + 1] != c) u = nxt[u];
				if(s[u + 1] == c) u ++;
				if(u < m) dp[i][u] = (dp[i - 1][j] + dp[i][u]) % mod;
			}
		}
	}
	int ans = 0;
	for (int i = 0; i <= m - 1; ++ i) ans = (ans + dp[n][i]) % mod;
	printf("%d", ans);
	return 0;
}

修复DNA

#include <bits/stdc++.h>
using namespace std;
int n, T = 1, idx = 0;
const int N = 1005;
char str[N];
bool dar[N];
int ne[N], f[N][N], q[N], tr[N][4];
int gett(char c)
{
	if(c == 'A') return 0;
	if(c == 'T') return 1;
	if(c == 'G') return 2;
	if(c == 'C') return 3;
	
}
void insert()
{
	int len = strlen(str + 1);
	int p = 0;
	for (int i = 1; i <= len; ++ i)
	{
		int c = gett(str[i]);
		if(!tr[p][c]) tr[p][c] = ++idx, p = idx;
		else p = tr[p][c];
	}
	dar[p] = true;
}
void build_AC()
{
	int tt = 1, hh = 0;
	for (int i = 0; i < 4; ++ i) if(tr[0][i]) q[++ hh] = tr[0][i];
	while(tt <= hh)
	{
		int p = q[tt ++];
		for (int i = 0; i < 4; ++ i)
		{
			int x = tr[p][i];
			if(!x) tr[p][i] = tr[ne[p]][i];
			else ne[x] = tr[ne[p]][i], dar[x] |= dar[ne[x]], q[++ hh] = x;	
		}	
	} 
	return ;
}
int main()
{
	while(scanf("%d", &n) != EOF)
	{
		if(!n) break;
		memset(dar, 0, sizeof dar);
		memset(f, 0x3f, sizeof f);
		memset(tr, 0, sizeof tr);
		memset(ne, 0, sizeof(ne));
		idx = 0;
		for (int i =1 ; i <= n; ++ i)
		{
			scanf("%s", str + 1);
			insert();
		}
		build_AC();

		scanf("%s", str + 1);
		int m = strlen(str + 1);
		f[0][0] = 0;
		for (int i = 0; i <= m - 1; ++ i)
		{
			for (int j = 0; j <= idx; ++ j)
			{
				for (int k = 0; k < 4; ++ k)
				{
					int p = tr[j][k];
					if(!dar[p]) f[i + 1][p] = min(f[i + 1][p], f[i][j] + (k != gett(str[i + 1])));
				}
			}
		}
		int ans = 0x3f3f3f3f;
		for (int i = 0; i <= idx; ++ i) if(!dar[i]) ans = min(ans, f[m][i]);
		if(ans == 0x3f3f3f3f) ans = -1;
		printf("Case %d: %d\n", T ++, ans);
	}
	return 0;
}

状态压缩DP

小国王

#include <bits/stdc++.h>
using namespace std;
const int N = 1030;
int n, a[1025][25], cnt = 0, K, b[25], num[1025];
typedef long long ll;
ll dp[2][105][1025], ans = 0;
void dfs(int x)
{
	if(x == n + 1)
	{
		int len = 0;
		for (int i = 1; i <= n; ++ i) if(b[i]) len ++;
		if(len <= K)
		{
			cnt ++, num[cnt] = len;
			for (int i = 1; i <= n; ++ i) a[cnt][i] = b[i];
			dp[1][num[cnt]][cnt] = 1ll;
		}
		return ;
	}
	if(!(b[x - 1])) b[x] = 1, dfs(x + 1);
	b[x] = 0, dfs(x + 1);
	return ;
}
bool check(int x, int y)
{
	for (int i = 1; i <= n; ++ i)
	{
		if(a[x][i] && a[y][i]) return false;
		if(a[x][i] && a[y][i + 1]) return false;
		if(a[x][i + 1] && a[y][i]) return false;
		if(a[x][i] && a[y][i - 1]) return false;
		if(a[x][i - 1] && a[y][i]) return false;
	}
	return true;
}
int main()
{
	scanf("%d %d", &n, &K);
	dfs(1);
	for (int i = 2; i <= n; ++ i)
	{
		for (int k = 0; k <= K; ++ k)
		{
			for (int x = 1; x <= cnt; ++ x)
			{
				dp[i & 1][k][x] = 0;
			}
		}
		for (int k = 0; k <= K; ++ k)
		{
			for (int x = 1; x <= cnt; ++ x)
			{
				for (int y = 1; y <= cnt; ++ y)
				{
					if(check(x, y) && num[x] <= k && k - num[x] >= num[y]) dp[i & 1][k][x] += dp[i & 1 ^ 1][k - num[x]][y];
				}
			}
		}
	}
	for (int i = 1; i <= cnt; ++ i) ans += dp[n & 1][K][i];
	printf("%lld", ans);
	return 0;
}

区间DP

环形石子合并

#include <bits/stdc++.h>
using namespace std;
const int N = 405;
int n, dpm[N][N], dpx[N][N], a[N], sum[N];
int ansm = 0x3f3f3f3f, ansx = 0;
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]), a[i + n] = a[i];
	memset(dpm, 0x3f, sizeof dpm);
	for (int i = 1; i <= n + n; ++ i) dpm[i][i] = dpx[i][i] = 0;
	for (int i = 1; i <= n + n; ++ i) sum[i] = sum[i - 1] + a[i];
	for (int len = 2; len <= n; ++ len)
	{
		for (int i = 1; i + len - 1 <= n + n; ++ i)
		{
			int j = i + len - 1;
			for (int k = i; k <= j - 1; ++ k)
			{
				dpx[i][j] = max(dpx[i][j], dpx[i][k] + dpx[k + 1][j] + sum[j] - sum[i - 1]);
				dpm[i][j] = min(dpm[i][j], dpm[i][k] + dpm[k + 1][j] + sum[j] - sum[i - 1]);
			}
		}
	}
	for (int i = 1; i <= n; ++ i)
	{
		ansm = min(ansm, dpm[i][i + n - 1]);
		ansx = max(ansx, dpx[i][i + n - 1]);
	}
	printf("%d\n%d", ansm, ansx);
}

树形DP

树的最长路径

#include <bits/stdc++.h>
using namespace std;
const int N = 10004;
int n, dp[N][2], ans = 0;
struct edge
{
	int v, w;
};
vector<edge> g[N];
void dfs(int x, int fa)
{
	for (int i = 0; i < g[x].size(); ++ i)
	{
		int y = g[x][i].v, w = g[x][i].w;
		if(y == fa) continue;
		dfs(y, x);
		if(dp[x][0] <= dp[y][0] + w) 
		{
			dp[x][1] = dp[x][0], dp[x][0] = dp[y][0] + w;
		}
		else if(dp[x][1] < dp[y][0] + w) dp[x][1] = dp[y][0] + w;
	}
	return ;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n - 1; ++ i)
	{
		int u, v, w;
		scanf("%d %d %d", &u, &v, &w);
		g[u].push_back((edge){v, w});
		g[v].push_back((edge){u, w});
	} 
	dfs(1, 0);
	for (int i = 1; i <= n; ++i) ans = max(ans, dp[i][0] + dp[i][1]);
	printf("%d", ans);
	return 0;
}
/*
只需要计算一个节点的最长路径和次长路径 
*/

数位DP

度的数量

#include <bits/stdc++.h>
using namespace std;
const int N = 35;
int l, r, k, b, f[N][N];
void init()
{
	f[0][0] = 1;
	for (int i = 1; i <= 31; ++ i)
	{
		for (int j = 0; j <= i; ++ j)
		{
			if(!j) f[i][j] = 1;
			else f[i][j] = f[i - 1][j] + f[i - 1][j - 1];
		}
	}
}
int dp(int n)
{
	int res = 0, last = 0;
	vector<int> nums;
	
	while(n)
	{
		nums.push_back(n % b);
		n /= b;
	}
	
	for (int i = nums.size() - 1; i >= 0; -- i)
	{
		int x = nums[i];
		if(x)
		{
			res += f[i][k - last];
			if(x > 1)
			{
				if(k - last - 1 >= 0) res += f[i][k - last - 1];
				break;
			}
			else 
			{
				last ++;
				if(last > k) break;
			}
		}
		
		if(!i && k == last) res += 1;
	}
	return res;
}
int main()
{
	scanf("%d %d %d %d", &l, &r, &k, &b);
	init();
	printf("%d", dp(r) - dp(l - 1));
	return 0;
}

数字游戏

#include <bits/stdc++.h>
using namespace std;
const int N = 35;
int l, r, f[N][11];
void init()
{
	for (int x = 0; x <= 9; ++ x) f[1][x] = 1; 
	for (int i = 2; i <= 31; ++ i)
	{
		for (int x = 9; x >= 0; -- x)
		{
			for (int y = x; y <= 9; ++ y)
			{
				f[i][x] += f[i - 1][y]; 
			}
		}
	}
	return ;
}
int dp(int n)
{
	if(n == 0) return 1;
	int res = 0, last = 0;
	vector<int> nums;
	while(n)
	{
		nums.push_back(n % 10);
		n /= 10;
	}
	for (int i = nums.size() - 1; i >= 0; -- i)
	{
		int x = nums[i];
		if(x >= last) for (int j = last; j <= x - 1; ++ j) res += f[i + 1][j];
		else break;
		if(!i && x >= last) res ++;
		last = x;
	}
	return res;
}
int main()
{
	init();
	while(scanf("%d %d", &l, &r) != EOF)
	{
		printf("%d\n", dp(r) - dp(l - 1));
	}
	return 0;
}

Windy数

#include <bits/stdc++.h>
using namespace std;
int f[35][11], l, r;
void init()
{
	for (int x = 0; x <= 9; ++ x)  f[1][x] = 1;
	for (int i = 2; i <= 31; ++ i)
	{
		for (int x = 0; x <= 9; ++ x)
		{
			for (int y = 0; y <= x - 2; ++ y) f[i][x] += f[i - 1][y];
			for (int y = x + 2; y <= 9; ++ y) f[i][x] += f[i - 1][y];
		}
	}
	return ;
}
int dp(int n)
{
	if(n == 0) return 1;
	int res = 0, last = -1;
	vector<int> nums;
	while(n)
	{
		nums.push_back(n % 10);
		n /= 10;
	}
	for (int i = nums.size() - 1; i >= 0; -- i)
	{
		int x = nums[i];
		for (int y = 0; y <= x - 1; ++ y)
		{
			if(abs(y - last) >= 2) res += f[i + 1][y];
		}
		if(abs(x - last) < 2) break;
		if(!i) res ++;
		last = x;
	}
	for (int i = 1; i <= nums.size() - 1; ++ i) 
	{
		for (int j = 1; j <= 9; ++ j) res += f[i][j];
	} 
	res ++;
	return res;
}
int main()
{
	init();
	scanf("%d %d", &l, &r);
	printf("%d", dp(r) - dp(l - 1));
	return 0;
}

数字游戏 II

#include <bits/stdc++.h>
using namespace std;
int f[11][11][105], p, l, r;
void init()
{
	memset(f, 0, sizeof(f));
	f[0][0][0] = 1;
	for (int i = 1; i <= 10; ++ i)
	{
		for (int x = 0; x <= 9; ++ x)
		{
			for (int y = 0; y <= 9; ++ y)
			{
				for (int k = 0; k <= p - 1; ++ k) f[i][x][(k + x) % p] += f[i - 1][y][k];
			}
		}
	}
	return ;
}
int dp(int n)
{
	int res = 0, last = 0;
	vector<int> nums;
	if(n == 0) return 1;
	while(n)
	{
		nums.push_back(n % 10);
		n /= 10;
	}
	
	for (int i = nums.size() - 1; i >= 0; -- i)
	{
		int x = nums[i];
		for (int j = 0; j <= x - 1; ++ j)
		{
			for (int k = 0; k <= 9; ++ k) res += f[i][k][(((p - j - last) % p) + p) % p];
		}
		last += x;
		if(!i && last % p == 0) res ++; 
	}
	return res;
}
int main()
{
	while(scanf("%d %d %d", &l, &r, &p) != EOF)
	{
		init();
		printf("%d\n", dp(r) - dp(l - 1));	
	}
	
	return 0;
}
posted @ 2025-02-13 10:40  Helioca  阅读(5)  评论(0)    收藏  举报
Document