您的位置:首页 > 其它

动态规划总结

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: