动态规划总结
2016-11-08 16:37
232 查看
//动态规划 //1.经典模型:数字三角形 //*记忆化搜索 int dfs(int y,int x){ if(y==n) return value[y][x]; if(dp[y][x] != -1) return dp[y][x]; dp[y][x] = value[y][x] + max(dfs(y+1,x),dfs(y+1,x+1)); return dp[y][x]; } int main(){ cin>>n; for(int i = 1;i <=n;i++){ for(int j = 1;j <= i;j++){ cin>>value[i][j]; } } memset(dp,-1,sizeof(dp)); dfs(1,1); cout<<dp[1][1]; return 0; } //*必须经过一个点:”必须“转化为最优 map[n/2][n/2] += hehe; for(int i = 1;i <= n;i++){ for(int j = 1;j <= i;j++){ dp[i][j] = max(dp[i-1][j],dp[i-1][j-1]) + map[i][j]; ans = max(dp[i][j],ans); } } cout<<ans-hehe; //*对一个数取余:加状态 dp[1][1][map[1][1]%100] = 1; for(int i = 2;i <= n;i++){ for(int j = 1;j <= i;j++){ for(int k = 0;k <= 99;k++){ if(dp[i-1][j-1][k] || dp[i-1][j][k]){ dp[i][j][(k+map[i][j])%100] = 1; if(i == n) ans = max(ans,(k+map[i][j])%100); } } } } cout<<ans; //*第k大路线 fo(i,1,n){ fo(j,1,i){ val[i][j] = read(); } } fo(i,1,n){ dp [i][1] = val [i]; cnt [i] = 1; } int p1,p2; fd(i,1,n-1){ fo(j,1,i){ p1 = p2 = 1; while(cnt[i][j] < k && (p1 <= cnt[i+1][j] || p2 <= cnt[i+1][j+1])){ if(p1 <= cnt[i+1][j] && (dp[i+1][j][p1] >= dp[i+1][j+1][p2] || p2 > cnt[i+1][j+1])) dp[i][j][++cnt[i][j]] = val[i][j] + dp[i+1][j][p1++]; else if(p2 <= cnt[i+1][j+1] && (dp[i+1][j][p1] < dp[i+1][j+1][p2] || p1 > cnt[i+1][j]))dp[i][j][++cnt[i][j]] = val[i][j] + dp[i+1][j+1][p2++]; } sort(dp[i][j]+1,dp[i][j]+cnt[i][j]+1,cmp); } } cout<<dp[1][1][k]; //2.经典模型:背包 //*01背包、完全背包、多重背包 for(int i = 1;i <= n;i++){ if(a[i] == -1){//顺序滚动数组 for(int j = w[i];j <= m;j++){ dp[j] = max(dp[j],dp[j-w[i]]+v[i]); } } if(a[i] == 1){//逆序滚动数组 for(int j = m;j >= w[i];j--){ dp[j] = max(dp[j],dp[j-w[i]]+v[i]); } } if(a[i] > 1){//二进制拆包 if(a[i] * w[i] >= m){ for(int j = w[i];j <= m;j++){ dp[j] = max(dp[j],dp[j-a[i]*w[i]]+a[i]*v[i]); } continue; } int k = 1; for(;k<a[i];){ for(int j = m;j >= w[i]*k;j--){ dp[j] = max(dp[j],dp[j-w[i]*k]+v[i]*k); } a[i] -= k; k = k<<1; } for(int j = m;j >= w[i]*a[i];j--){ dp[j] = max(dp[j],dp[j-w[i]*a[i]]+v[i]*a[i]); } } } cout<<dp[m]<<endl; //*分组背包 for(int i = 1;i <= cnt;i++){ now = tran[i]; for(int j = c;j >= 0;j--){ for(int t = 0;t < itm[now].size();t++){ if(j >= itm[now][t].w)dp[j] = max(dp[j],dp[j-itm[now][t].w] + itm[now][t].v); } } } //*依赖背包 for(int i = 1;i <= n;i++){ scanf("%d%d%d",&v,&p,&q); if(q == 0){ pt[++cnt] = i; vis[i] = 1; req[cnt] = v; mon[cnt] = p*v; }else{ tmp.w = v; tmp.v = p*v; bag[q].push_back(tmp); } } for(int i = 1;i <= cnt;i++){ ccnt ^= 1; int g = pt[i]; for(int j = req[i];j <= m;j++){ dp[ccnt][j] = max(dp[ccnt^1][j],dp[ccnt^1][j-req[i]] + mon[i]); } if(bag[g].size() >= 1){ for(int j = req[i] + bag[g][0].w;j <= m;j++){ dp[ccnt][j] = max(dp[ccnt][j],max(dp[ccnt^1][j],dp[ccnt^1][j-req[i]-bag[g][0].w] + mon[i] + bag[g][0].v)); } } if(bag[g].size() >= 2){ for(int j = req[i] + bag[g][1].w;j <= m;j++){ dp[ccnt][j] = max(dp[ccnt][j],max(dp[ccnt^1][j],dp[ccnt^1][j-req[i]-bag[g][1].w] + mon[i] + bag[g][1].v)); } for(int j = req[i] + bag[g][1].w + bag[g][0].w;j <= m;j++){ dp[ccnt][j] = max(dp[ccnt][j],max(dp[ccnt^1][j],dp[ccnt^1][j-req[i]-bag[g][1].w-bag[g][0].w] + mon[i] + bag[g][1].v + bag[g][0].v)); } } for(int j = 0;j <= m;j++){ dp[ccnt][j] = max(dp[ccnt^1][j],dp[ccnt][j]); } } cout<<dp[ccnt][m]; //*二维费用背包 f[0][0]=1; for (int i=1;i<=n;i++) { if (a[i]>k)continue; for (int j=m;j>=1;j--) for(int l=k;l>=a[i];l--) f[j][l]|=f[j-1][l-a[i]]; } for (int j=k;j>=0;j--) for (int i=m;i>=0;i--) if (f[i][j]){printf("%d\n",j);return 0;} //*重量特别大:用价值当费用求最小值 fo(i,1,n){ w[i] = read();v[i] = read(); mn += v[i]; } memset(dp,127/3,sizeof(dp)); dp[0] = 0; fo(i,1,n){ fd(j,v[i],mn){ dp[j] = min(dp[j],dp[j-v[i]] + w[i]); if(dp[j] <= m) ans = max(j,ans); } } cout<<ans; //3.经典模型:区间 //* 能量项链:断环为链 for(int i = 1;i <= n;i++){ cin>>value[i]; value[i+n] = value[i]; } for(int j = 2;j <= n + n;j++){ for(int i = j - 1;i >= 1 && j - i <= n;i--){ for(int k = i;k < j;k++){ dp[i][j] = max(dp[i][j],dp[i][k] + dp[k+1][j] + value[i] * value[j+1] * value[k+1]); } } } int ans = 0; for(int i = 1;i <= n;i++) ans = max(ans,dp[i][i+n-1]); cout<<ans; //*石子归并(最大最小值) cin>>n; for(int i = 1;i <= n;i++){ cin>>value[i]; value[i+n] = value[i]; sum[i] = sum[i-1] + value[i]; } for(int i = 1;i <= n;i++) sum[i+n] = sum[i] + sum ; for(int j = 2;j <= n + n;j++){ for(int i = j - 1;i >= 1 && j - i + 1 <= n;i--){ dp[i][j] = maxnum; for(int k = i;k < j;k++){ dp[i][j] = min(dp[i][j],dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]); } for(int k = i;k < j;k++){ dps[i][j] = max(dps[i][j],dps[i][k] + dps[k+1][j] + sum[j] - sum[i-1]); } } } int ans = maxnum; for(int i = 1;i <= n;i++) ans = min(ans,dp[i][i+n-1]); cout<<ans<<endl; ans = 0; for(int i = 1;i <= n;i++) ans = max(ans,dps[i][i+n-1]); cout<<ans; //*石子归并加强1:四边形不等式加速 for(int l = 2;l <= n;l++){ for(int i = 1;i <= n - l + 1;i++){ j = i + l - 1; dp[i][j] = maxnum; for(int k = a[i][j-1];k <= a[i+1][j];k++){ if(dp[i][j] > dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]){ dp[i][j] = dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]; a[i][j] = k; } } } } cout<<dp[1] ; //*石子归并加强2:三颗石子合并,开一个辅助数组记录两堆合并结果 n=read(); rep(i,1,n) rep(j,1,n)f1[i][j]=f2[i][j]=INF; rep(i,1,n)a[i]=a[i-1]+read(); rep(i,1,n)f2[i][i]=0; rep(i,1,n-1)f1[i][i+1]=a[i+1]-a[i-1]; rep(len,3,n) rep(i,1,n-len+1){ int j=i+len-1; rep(k,i,j-1)f2[i][j]=min(f2[i][j],f1[i][k]+f2[k+1][j]+a[j]-a[k]); rep(k,i,j-1)f1[i][j]=min(f1[i][j],f2[i][k]+f2[k+1][j]+a[j]-a[i-1]); } cout<<f2[1] <<endl; //*加分二叉树:输出方案 void preorder(int i,int j){ int k = root[i][j]; if(k == 0) return; cout<<k<<" "; preorder(i,k-1); preorder(k+1,j); } int main(){ memset(root,0,sizeof(root)); memset(f,0,sizeof(f)); memset(d,0,sizeof(d)); cin>>n; for(int i=1;i <= n;i++) cin>>d[i]; for(int i = 0;i <= n;i++){ f[i][i] = d[i]; root[i][i] = i; f[i+1][i] = 1; } for(int p = 1;p < n;p++){ for(int i = 1;i <= n - p;i++){ int j = i+p; for(int k = i;k <= j;k++){ int temp = f[i][k-1] * f[k+1][j] + d[k]; if(temp > f[i][j]) f[i][j] = temp,root[i][j] = k; } } } cout<<f[1] <<endl; preorder(1,n); return 0; } //*最优矩阵链乘 for(int i = 1;i <= n+1;i++){ cin>>a[i]; } for(int i = 1;i <= n+1;i++){ for(int j = 1;j <= n+1;j++){ f[i][j] = maxint; } } long long j,tmp; for(int l = 3;l <= n+1;l++){ for(int i = 1;i <= n-1;i++){ j = i + l - 1; for(int k = i + 1;k <= j-1;k++){ tmp = a[i] * a[k] * a[j]; if(k - i >= 2) tmp += f[i][k]; if(j - k >= 2) tmp += f[k][j]; f[i][j] = min(f[i][j],tmp); } } } cout<<f[1][n+1]; //*括号序列 int main(){ scanf("%s",a+1); a[0] = '!'; n = strlen(a) - 1; for(int i = 0;i <= n;i++){ for(int j = 0;j <= n;j++){ f[i][j] = 999; if(j == i - 1) f[i][j] = 0; if(i == j) f[i][j] = 1; } } for(int l = 2;l <= n;l++){ for(int i = 1;i <= n - l + 1;i++){ int j = i + l - 1; if((a[i] == '(' && a[j] == ')') || (a[i] == '[' && a[j] == ']')) f[i][j] = min(f[i][j],f[i+1][j-1]); if(a[i] == '(' || a[i] == '[') f[i][j] = min(f[i][j],f[i+1][j] + 1); if(a[j] == ')' || a[j] == ']') f[i][j] = min(f[i][j],f[i][j-1] + 1); for(int k = i;k < j;k++) f[i][j] = min(f[i][j],f[i][k] + f[k+1][j]); } } cout<<f[1] ; return 0; } //4.经典模型:序列 //*LIS for(int i = 1;i <= n;i++){ dp[i] = 1; for(int j = 1;j < i;j++){ if(orz[i] > orz[j])dp[i] = max(dp[i],dp[j]+1); ans = max(ans,dp[i]); } } cout<<ans; //*二分优化LIS:辅助数组 int main(){ cin>>n; for(int i = 1;i <= n;i++) scanf("%d",&a[i]); for(int i = 1;i <= n;i++) g[i] = inf; for(int i = 1;i <= n;i++){ int k = lower_bound(g+1,g+1+n,a[i]) - g; d[i] = k; g[k] = a[i]; if(ans < d[i]) ans = d[i]; } cout<<ans; return 0; } //*LCS fo(i,1,n){ fo(j,1,n){ if(a[i] == b[j]) dp[i][j] = dp[i-1][j-1] + 1; else dp[i][j] = max(dp[i-1][j],dp[i][j-1]); } } //*LCS两序列对应相同:转化为LIS n = read(); fo(i,1,n) a[i] = read(); fo(i,1,n){ b[i] = read(); tran[b[i]] = i; } fo(i,1,n){ b[tran[a[i]]] = i; } memset(g,127/3,sizeof(g)); int ans = 0; fo(i,1,n){ int k = lower_bound(g+1,g+1+n,b[i]) - g; d[i] = k; g[k] = b[i]; ans = max(ans,d[i]); } cout<<ans; //5.树形dp //*选课:左儿子右兄弟 void dfs(int item,int room){ if(dp[item][room] >=0) return; if(item == 0 || room == 0){ dp[item][room] = 0; return; } dfs(brother[item],room); for(int k = 0;k < room;k++){ dfs(brother[item],k); dfs(child[item],room-k-1); dp[item][room] = max(dp[item][room],max(dp[brother[item]][room],dp[brother[item]][k] + dp[child[item]][room-k-1] + value[item])); } return; } int main(){ memset(dp,-1,sizeof(dp)); cin>>n>>m; for(int i = 1;i <= n;i++){ cin>>tmpa>>tmpb; value[i] = tmpb; if(tmpa == 0) tmpa = n + 1; brother[i] = child[tmpa]; child[tmpa] = i; } dfs(child[n+1],m); cout<<dp[child[n+1]][m]; return 0; } //*没有上司的舞会 int n,happy[maxn],vis[maxn],dp[maxn][2],root; vector<int> l[maxn]; void input(){ cin>>n; for(int i = 1;i <= n;i++){ scanf("%d",&happy[i]); } int k,t; for(int i = 1;i < n;i++){ scanf("%d%d",&t,&k);//k boss vis[t] = 1; l[k].push_back(t); } for(int i = 1;i <= n;i++){ if(!vis[i]) root = i; dp[i][0] = dp[i][1] = -inf; } } void dfs(int now){ dp[now][1] = happy[now]; dp[now][0] = 0; for(int i = 0;i < l[now].size();i++){ dfs(l[now][i]); dp[now][1] += dp[l[now][i]][0]; dp[now][0] += max(dp[l[now][i]][1],dp[l[now][i]][0]); } } int main(){ input(); dfs(root); cout<<max(dp[root][0],dp[root][1]); return 0; } //*医疗两仪师:把一棵树分成k+1个联通块,使得每一个连通块有且仅有一个标记点,求方案数,方程都是一样的,给两个版本 void input(){ cin>>n; int cmd; for(int i = 1;i < n;i++){ cin>>cmd; add_edge(cmd,i); } for(int i = 0;i < n;i++){ cin>>col[i]; } } void dfs(int u){ if(!head[u]){ if(col[u]) f[u][1] = 1; else f[u][0] = 1; return; } ll sum = 1; int v; if(col[u]){ for(int i = head[u];i;i = e[i].nxt){ v = e[i].to; dfs(v); sum = q_mul(sum,f[v][0] + f[v][1]); } f[u][1] = sum; return; }else{ for(int i = head[u];i;i = e[i].nxt){ v = e[i].to; dfs(v); sum = q_mul(sum,f[v][0] + f[v][1]); } f[u][0] = sum; for(int i = head[u];i;i = e[i].nxt){ v = e[i].to; f[u][1] += q_mul(f[v][1],q_mul(sum,q_pow(f[v][0] + f[v][1],mod-2))); } return; } } int main(){ freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); ios::sync_with_stdio(false); input(); dfs(0); cout<<f[0][1]; return 0; } ll f[MAXN][2]; int point[MAXN] = {0}, nxt[MAXN * 2] = {0}, v[MAXN * 2] = {0}, tot = 0; bool color[MAXN] = {0}; int n; inline void addedge(int x, int y) { tot++; nxt[tot] = point[x]; point[x] = tot; v[tot] = y; } void dfs(int now, int father) { f[now][0] = 1; f[now][1] = 0; for (int tmp = point[now]; tmp; tmp = nxt[tmp]) if (v[tmp] != father) { dfs(v[tmp], now); f[now][1] = (f[now][1] * f[v[tmp]][0]) % MOD; f[now][1] = (f[now][1] + f[now][0] * f[v[tmp]][1]) % MOD; f[now][0] = (f[now][0] * f[v[tmp]][0]) % MOD; } if (color[now]) f[now][1] = f[now][0]; else f[now][0] = (f[now][0] + f[now][1]) % MOD; } int main() { freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); scanf("%d", &n); for (int i = 2; i <= n; i++) { int x; scanf("%d", &x); addedge(i, x + 1); addedge(x + 1, i); } for (int i = 1; i <= n; i++) { int x; scanf("%d", &x); if (x == 1) color[i] = true; else color[i] = false; } dfs(1, 0); cout << f[1][1] << endl; } /***习题整理***/ /* 例1.子串 1.f[i][j][k]表示ai,bj为结尾匹配k个,f[i][j][k] = f[i-1][j-1][k] + f[1...i-1][j-1][k-1] 2.f[i][j][k]表示匹配到i,j匹配k个,f[i][j][k] = f[i-1][j-1][k] + f[i-x...i][j-x...j][k-1] if matches 显然前者可以优化后者不行 */ 1. dp[0][0][0] = 1; fo(i,0,n) sum[0][i][0] = 1; fo(k,1,K){ cnt^=1; fo(i,1,n){ fo(j,1,m){ if(a[i] == b[j]){ dp[cnt][i][j] = (dp[cnt][i-1][j-1] + sum[cnt^1][i-1][j-1]) % mod; } sum[cnt][i][j] = (sum[cnt][i-1][j] + dp[cnt][i][j]) % mod; } } memset(sum[cnt^1],0,sizeof(sum[cnt^1])); memset(dp[cnt^1],0,sizeof(dp[cnt^1])); } cout<<sum[cnt] [m]; 2. fo(i,0,n) dp[0][i][0] = 1; fo(k,1,K){ cnt^=1; fo(i,1,n){ fo(j,1,m){ fo(x,0,9999){ if(a[i-x] != b[j-x] || i <x || j < x) break; dp[cnt][i][j] = (dp[cnt][i][j] + dp[cnt^1][i-x-1][j-x-1]) % mod; } dp[cnt][i][j] = (dp[cnt][i][j] + dp[cnt][i-1][j]) % mod; } } memset(sum[cnt^1],0,sizeof(sum[cnt^1])); memset(dp[cnt^1],0,sizeof(dp[cnt^1])); } cout<<dp[cnt] [m]; /* 例2:k车问题,在n*m棋盘上放置K个车,使没有一个车同时被两个车攻击,求方案数 i:行数,j:只有一个车且安全的列数,l:只有一个车且不安全的列数,p:有两个车的列数 */ f[0][0][0][0] = 1; for(int i = 1;i <= n;i++){ cnt ^= 1; for(int j = 0;j <= n<<1;j++){ for(int l = 0;l <= n<<1;l+=2){ for(int p = 0;p <= n;p++){ f[cnt][j][l][p] = f[cnt^1][j][l][p]; if(j > 0) f[cnt][j][l][p] += f[cnt^1][j-1][l][p]*(m-j-p-l+1); if(p > 0) f[cnt][j][l][p] += f[cnt^1][j+1][l][p-1]*(j+1); if(l > 1) f[cnt][j][l][p] += (f[cnt^1][j][l-2][p]*(m-j-l-p+2)*(m-j-l-p+1))>>1; f[cnt][j][l][p] %= mod; if(i == n && j + l + (p<<1) == k){ ans = (ans + f[cnt][j][l][p]) % mod; } } } } } cout<<ans; /* 例3:滑雪,记忆化搜索 */ int dp(int i,int j){ if(f[i][j]) return f[i][j]; f[i][j] = 1; int y,x; for(int t = 0;t < 4;t++){ y = i + dy[t]; x = j + dx[t]; if(jud(y,x) && h[i][j] > h[y][x]) f[i][j] = max(f[i][j],1 + dp(y,x)); } return f[i][j]; } int main(){ cin>>r>>c; for(int i = 1;i <= r;i++){ for(int j = 1;j <= c;j++){ cin>>h[i][j]; } } for(int i = 1;i <= r;i++){ for(int j = 1;j <= c;j++){//attention! ans = max(ans,dp(i,j)); } } cout<<ans; return 0; } /* 例4:传纸条:“必须”变“最优“ + 优化空间 */ for(int i = 1;i <= m;i++){ for(int j = 1;j <= n;j++){ scanf("%d",&v[i][j]); } } for(int l = 2;l <= n+m;l++) for(int y = 1;y <= m && y < l;y++){ for(int i = 1;i <= m && i < l;i++){ int x = l - y, j = l - i; f[l][i][y] = max(max(f[l-1][i][y],f[l-1][i-1][y]),max(f[l-1][i][y-1],f[l-1][i-1][y-1])); f[l][i][y] += v[i][j]; if(!(i == y && j == x)) f[l][i][y] += v[y][x]; } } cout<<f[m+n][m][m]; /* 例5:划分大理石,价值为i([1,6])的物品各ai件,问能否划分成价值相等的两部分 总价值为奇数不能划分,多重背包判断能否实现价值为sumv/2 */ int main(){ bool ok = true,ans = false; while(ok){ ok = false; n = sum = 0; for(int i = 1;i <= 6;i++){ scanf("%d",&a[i]); if(a[i]) ok = true; sum += a[i]*i; for(int j = 1;j <= a[i];j<<=1){ w[++n] = j * i; a[i] -= j; } w[++n] = a[i] * i; } if(!ok) break; if(sum & 1){ puts("Can't"); continue; } memset(f,false,sizeof(f)); f[0] = true; for(int i = 1;i <= n;i++){ for(int j = sum >> 1;j >= w[i];j--){ if(f[j - w[i]]) f[j] = true; } if(f[sum>>1]){ ans = true; break; } } if(ans) puts("Can"); else puts("Can't"); } return 0; } /* 例6:集体舞,给一个正三角形,每一个点为一个小三角形,且分为两类,求种类相同的最大三角形面积 把大三角拆成小三角 */ int main(){ cin>>n; char cmd; sum[1] = 1; for(int i = 1;i <= n;i++){ for(int l = 1;l <= 2*(n-i) + 1;l++){ int j = i + l - 1; scanf("%c",&cmd); while(cmd != '-' && cmd != '#') scanf("%c",&cmd); if(cmd == '#') a[i][j] = 1; else a[i][j] = 2; } } for(int i = 3;i <= 2 * n - 1;i += 2) sum[i] = sum[i-2] + i; for(int i = 1;i <= n;i++){ for(int l = 1;l <= 2*(n-i) + 1;l++){ int j = i + l - 1; if(a[i][j] == 2) f[i][j] = 1; if(l & 1) if(a[i][j] == 2 && a[i][j+1] == 2 && a[i][j+2] == 2 && a[i+1][j+1] == 2) f[i][j] = 3; ans = max(ans,f[i][j]); } } for(int k = 5;k <= 2 * n - 1;k += 2){ for(int i = 1;i <= n;i++){ for(int l = 1;l <= 2*(n-i) + 1;l++){ int j = i + l - 1; if((l & 1) && f[i][j] >= k - 2 && f[i][j+2] >= k - 2 && f[i+1][j+1] >= k - 2){ f[i][j] = k; ans = max(ans,k); } } } } cout<<sum[ans]; return 0; } /* 例7:chopsticks,定义三元组(x,y,z)的代价为最小的两个数的差的平方,在n个数中选出m个三元组,求最小代价 经典题目,将原数列倒序排序,保证数的个数就可以保证最大的数z一定取到,剩下的两个数贪心选择相邻的 */ for(int i = 1;i <= m;i++){ for(int j = 1;j <= n;j++){ if(j < i * 3) dp[i][j] = 9876543212345L; else dp[i][j] = min(dp[i][j-1],dp[i-1][j-2] + (a[j] - a[j-1]) * (a[j] - a[j-1])); } } cout<<dp[m] ; /* 例8:自然数拆分,把一个数拆成若干数相加,加数可重复,分两种情况讨论:增加一个1,把以前的情况都加上1 */ dp[0][0] = 1; for(int i = 1;i <= n;i++){ for(int j = i;j <= n;j++){ dp[i][j] = (dp[i-1][j-1] + dp[i][j-i]) % mod; if(i > 1 && j == n) ans = (ans + dp[i][j]) % mod; } } cout<<ans; /* 例9:smrtfun, 有n个二元组(ai,bi),定义其价值为ai+bi,限制suma、sumb都为非负,求最大价值和 加一维记录suma,加上一个数保证其非负 */ int n,a[105],b[105],f[105][200015],suma = 100000,ans,bg = 100000,inf = 100005; int main(){ cin>>n; for(int i = 1;i <= n;i++){ scanf("%d%d",&a[i],&b[i]); if(a[i] >= 0) suma += a[i]; } for(int i = 0;i <= bg * 2;i++) f[1][i] = -inf; f[1][bg+a[1]] = b[1]; f[1][bg] = 0; for(int i = 2;i <= n;i++){ for(int j = 0;j <= bg * 2;j++){ f[i][j] = f[i-1][j]; if(j - a[i] >= 0 && j - a[i] <= bg * 2) f[i][j] = max(f[i][j],f[i-1][j-a[i]] + b[i]); if(j >= bg && f[i][j] >= 0) ans = max(ans,j + f[i][j] - bg); } } cout<<ans; return 0; } /* 例10:将一个自然数拆成若干个2的整数次方之和,求方案数 nlogn按照最大的数字分类讨论,n按有没有1讨论(这种讨论是常见套路) */ int main(){ cin>>n; f[0][0] = 1; for(int i = 1;i <= n;i++){ for(int j = 1,l = 1;l <= i;j++,l <<= 1){ h[i] = j; f[j][i] = f[j-1][i]; k = i - l; if(l >= k) f[j][i] = (f[j][i] + f[h[k]][k]) % mod; else f[j][i] = (f[j][i] + f[j][k]) % mod; } } cout<<f[h ] ; return 0; } int main(){ cin>>n; f[1] = 1; f[2] = 2; for(int i = 3;i <= n;i++){ if(!(i & 1)) f[i] = (f[i-1] + f[i>>1]) % mod; else f[i] = f[i-1]; } cout<<f ; return 0; } /* 例11:股票,1块钱买入卖出股票,交易数量可以是分数,求问最多赚多少钱 贪心购买 */ double a[1000005],ans; int main(){ cin>>n; for(int i = 1;i <= n;i++) scanf("%lf",&a[i]); ans = 1; for(int i = 1;i <= n;i++){ if(a[i] < a[i+1] && !ch) ch = i; else if(a[i] > a[i+1] && ch){ ans = ans / a[ch] * a[i]; ch = 0; } } pt = floor(ans + 0.5); cout<<pt; return 0; } /* 例12.任务安排:N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和(同一批任务将在同一时刻完成)。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。 费用提前计算 */ for(int i = 1;i <= n;i++){ for(int j = i;j >= 1;j--){ dp[i] = min(dp[i],dp[j-1] + (s + sumt[i] - sumt[j-1]) * (sumf - sumf[j-1])); } } /* 例13.盖房子:正方形嵌套 */ for(int i = 1;i <= n;i++){ for(int j = m;j >= 1;j--){ if(f[i][j]) f[i][j] = min(min(f[i-1][j],f[i-1][j+1]),f[i][j+1]) + 1; ans = max(ans,f[i][j]); } } /* 例14.mm不哭:提前计费 */ int main(){ cin>>n>>v; for(int i = 1;i <= n;i++){ scanf("%d%d",&mm[i].d,&mm[i].w); } sort(mm+1,mm+1+n,cmp); for(int i = 0;i <= n;i++){ for(int j = 0;j <= n;j++){ lf[i][j] = rf[i][j] = 1087654321; } } for(int i = 1;i <= n;i++) sumw[i] = sumw[i-1] + mm[i].w; lf[v][v] = rf[v][v] = 0; for(int l = 1;l <= n - 1;l++){ for(int i = max(v - l,1);i <= v;i++){ int j = i + l; if(j > n) continue; lf[i][j] = min(lf[i+1][j] + (mm[i+1].d - mm[i].d) * (sumw[i] + sumw - sumw[j]),rf[i+1][j] + (mm[j].d - mm[i].d) * (sumw[i] + sumw - sumw[j])); rf[i][j] = min(rf[i][j-1] + (mm[j].d - mm[j-1].d) * (sumw[i-1] + sumw - sumw[j-1]),lf[i][j-1] + (mm[j].d - mm[i].d) *(sumw[i-1] + sumw - sumw[j-1])); } } cout<<(lf[1] < rf[1] ? lf[1] : rf[1] ); return 0; } /* 例15.搭建双塔,n个石头高度为hi,求搭建两个一样的塔的最大高度 两个塔就本质上来说都是一致的,加一维表示差值,转移显然,注意初值设-1表示达不到 */ for(int i = 0;i <= n;i++){ for(int j = 0;j <= 2000;j++){ f[i][j] = -1; } } f[0][0] = 0; for(int i = 1;i <= n;i++){ for(int j = 0;j <= 2000;j++){ f[i][j] = max(f[i][j],f[i-1][j]); if(f[i-1][j] != -1){ f[i][j+a[i]] = max(f[i][j+a[i]],f[i-1][j]); if(a[i] <= j) f[i][j-a[i]] = max(f[i][j-a[i]],f[i-1][j] + a[i]); else f[i][a[i]-j] = max(f[i][a[i]-j],f[i-1][j] + j); } } } if(f [0]) cout<<f [0]; else cout<<"Impossible"; /* 例16.飞扬的小鸟,在某一位置点击升高yi,不点击降低xi,求到终点最少点几次,或最多能过几个管子 类似于完全背包,细节非常多 */ int main(){ cin>>n>>m>>k; for(int i = 0;i < n;i++){ cin>>up[i]>>down[i]; } int p,l,h; for(int i = 1;i <= n+1;i++) { for(int j = 0;j <= m;j++){ dp[i][j] = maxnum; } upp[i-1].high = m+1; upp[i-1].low = 0; } dp[0][0] = maxnum; int arrive = k; for(int i = 1;i <= k;i++){ cin>>p>>l>>h; upp[p].high = h; upp[p].low = l; vis[p] = 1; } for(int i = 1;i <= n;i++){ for(int j = 1;j <= m;j++){ if(j >= up[i-1]){//点1下,或者大于1下,相当于是一个混合背包 dp[i][j] = min(dp[i][j],min(dp[i-1][j-up[i-1]]+1,dp[i][j-up[i-1]]+1)); } if(j == m){//碰到天花板的情况单独讨论 for(int q = m-up[i-1] ;q <= m;q++) dp[i][j] = min(dp[i][j],min(dp[i-1][q] + 1,dp[i][q] + 1)); } }//往下走的情况 for(int j = upp[i].low+1;j < upp[i].high;j++) if(j + down[i-1] <=m) dp[i][j] = min(dp[i][j], dp[i-1][j+down[i-1]]); for(int j = 1;j <= upp[i].low;j++) dp[i][j] = maxnum; for(int j = upp[i].high;j <= m;j++) dp[i][j] = maxnum; } int cnt = k, ans = maxnum;//寻找在哪个管子处停止 for (int i = n; i >= 1; i--) { for (int j = upp[i].low+1; j <= upp[i].high-1; ++j) if (dp[i][j] < maxnum) ans = min(ans, dp[i][j]); if (ans != maxnum) break; if (upp[i].high <= m) cnt --; } if(cnt==k) printf("1\n%d\n", ans); else printf("0\n%d\n", cnt); return 0; } /* 例17.过河 压缩路径 */ int main(){ cin>>l>>s>>t>>m; int tmp,next,last = 0,cut = 0; for(int i = 1;i <= m;i++){ scanf("%d",&tmp); stone[i] = tmp; } sort(stone+1,stone+1+m,cmp); stone[m+1] = l; for(int i = 1;i <= m+1;i++){ tmp = stone[i]; tmp -= cut; int river = tmp - last - 1; int rec = river; river %= s*t*10; tmp = last+river+1; vis[tmp] = 1; last = tmp; if(i == m+1) l = tmp; } for(int i = 1;i <= l;i++){ dp[i] = maxint; } ans = maxint; for(int i = 0;i < l;i++){ if(vis[i]){ dp[i]++; } for(int j = s;j <= t;j++){ if(i+j>=l){ ans = min(ans,dp[i]); break; } dp[i+j] = dp[i+j] > dp[i] ? dp[i] : dp[i+j]; } } cout<<ans; return 0; }
相关文章推荐
- 《算法导论》学习总结 — 18.第15章 动态规划(3) 基础入门2
- 动态规划总结
- 动态规划题目总结(一)
- 动态规划 4、基础背包问题总结(多重背包与多重背包的转化)
- 关于动态规划与备忘录方法的总结
- 《算法导论》第15章 动态规划总结
- 《算法导论》读书笔记之第15章 动态规划[总结]
- 动态规划总结
- 动态规划 4、基础背包问题总结(从01开始)
- 【转】动态规划总结
- poj 动态规划总结,在网上找的!!!!
- 动态规划整理总结(未完待续)
- 动态规划题目总结(一)
- 【总结】《算法设计与分析》第三章动态规划
- 动态规划“数塔”类型题目总结
- 《算法导论》学习总结 — 16.第15章 动态规划(1) 基本入门
- 《算法导论》学习总结 — 20.第15章 动态规划(5) 分析几道DP题
- 《算法导论》读书笔记之第15章 动态规划[总结]
- 杭电acm step 动态规划专题总结(1)简单的动态规划问题
- 简单动态规划总结