kuangbin 区间dp
A - Cake
题目大意:给你一个n个顶点(n<=100)的多边形和每两个点连边的消耗,让你求把这个多边形全部切成三角形所需要的最小消耗,如果这个多边形为凹多边形则输出无解。
思路:先求一个凸包,看凸包里的点是不是n个,不是n个输出无解,求完凸包之后,点都是按顺时针排的,我们用dp[ i ][ j ]表示,i 到 j 的折线和 i 连 j的直线围成的多边形
的最小消耗。
状态转移方程:dp[ i ][ j ]=min( dp[ i ][ j ] , dp[ i ][ k ]+dp[ k ][ j ]+cost[ i ][ k ]+cost[ k ][ j ] ) ( i<k<j )
则dp[ 0 ][ n-1 ]即为答案。
#include<bits/stdc++.h>
using namespace std;
const int N=;
const int inf=0x3f3f3f3f;
int n,tot,dp[N][N],cost[N][N],mod;
struct point
{
int x,y;
point(int _x=,int _y=){x=_x; y=_y;}
point operator -(const point &rhs)const
{
return point(x-rhs.x,y-rhs.y);
}
}p[N],cp[N];
typedef point vec;
int cross(const vec &a,const vec &b)
{
return (a.x*b.y)-(a.y*b.x);
}
int dis(point a,point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(const point &a,const point &b)
{
int z=cross(a-p[],b-p[]);
if(z>||(z== && dis(p[],a)<dis(p[],b)))
return ;
else return ;
}
void get_cp()
{
int k=; tot=;
for(int i=;i<n;i++)
if(p[i].y<p[k].y || p[i].y==p[k].y && p[i].x<p[k].x) k=i;
swap(p[],p[k]);
sort(p+,p+n,cmp);
tot=,cp[]=p[];cp[]=p[];
for(int i=;i<n;i++)
{
while(tot> && cross(cp[tot-]-cp[tot-],p[i]-cp[tot-])>) tot--;
cp[tot++]=p[i];
}
}
void init()
{
memset(dp,-,sizeof(dp));
memset(cost,,sizeof(cost));
}
int solve(int l,int r)
{
if(dp[l][r]!=-) return dp[l][r];
if(r-l<=) return ;
dp[l][r]=inf;
for(int k=l+;k<=r-;k++)
dp[l][r]=min(solve(l,k)+solve(k,r)+cost[l][k]+cost[k][r],dp[l][r]);
return dp[l][r];
}
int main()
{
while(scanf("%d%d",&n,&mod)!=EOF)
{
for(int i=;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y);
get_cp();
if(tot<n)
{
puts("I can't cut.");
continue;
}
init();
for(int i=;i<n;i++)
for(int j=i+;j<n;j++)
cost[i][j]=cost[j][i]=abs(cp[i].x+cp[j].x)*abs(cp[i].y+cp[j].y)%mod; printf("%d\n",solve(,n-));
} return ;
}
B - Halloween Costumes
题目大意:有一个人去参加n场派对,不同种类的派对需要的衣服是不一样的,问你他最少需要多少件衣服,他最多可以套无限个衣服,脱掉的衣服不能重新利用。
思路:用dp[ i ][ j ]表示从第 i 个派对开始 到 第 j 个派对结束最少需要多少衣服。
状态转移方程:
dp[ i ][ j ]=dp[ i ][ j-1 ] + 1
dp[ i ][ j ]=min( dp[ i ][ j ] , dp[ i ][ k ]+dp[ k+1 ][ j-1 ]) ( i <k<j || 第k个派对种类和第 j 种相同)
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=;
int dp[N][N],n,a[N];
int solve(int l,int r)
{
if(dp[l][r]!=-) return dp[l][r];
if(l==r) return ;
if(l>r) return ;
dp[l][r]=solve(l,r-)+;
for(int i=l;i<r;i++)
{
if(a[i]!=a[r]) continue;
dp[l][r]=min(dp[l][r],solve(l,i)+solve(i+,r-));
}
return dp[l][r];
}
int main()
{
int T; scanf("%d",&T);
for(int cas=;cas<=T;cas++)
{
memset(dp,-,sizeof(dp));
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
int ans=solve(,n);
printf("Case %d: %d\n",cas,ans);
}
return ;
}
C - Brackets
题目大意:给你一个括号的序列,问你最多的一种匹配里面由多少个括号。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=;
int dp[N][N],n;
char s[N];
int solve(int i,int j)
{
if(dp[i][j]!=-) return dp[i][j];
if(i>=j) return ;
dp[i][j]=max(solve(i+,j),solve(i,j-));
for(int k=i;k<j;k++)
{
if(s[j]==')' && s[k]=='(')
dp[i][j]=max(dp[i][j],solve(i,k-)+solve(k+,j-)+);
if(s[j]==']' && s[k]=='[')
dp[i][j]=max(dp[i][j],solve(i,k-)+solve(k+,j-)+);
}
return dp[i][j];
}
int main()
{
while(scanf("%s",s+)!=EOF)
{
if(s[]=='e') break;
n=strlen(s+);
memset(dp,-,sizeof(dp));
printf("%d\n",*solve(,n));
}
return ;
}
D - Coloring Brackets
题目大意:给你一串匹配号的括号,让你给这些括号染色,染色的规则如下:
1.每个括号只能染红色,蓝色,或者不然色。
2.匹配的括号只能有一个被染色。
3.相邻的括号被染的颜色不能相同,但可以都不染色。
思路:用dp[ i ][ j ][ p ][ q ]表示区间 i 到 j 之间且第 i 个括号的染色情况为p ,第 j 个括号的染色情况为q 的方案数。
状态转移方程分i,j 是否匹配,如果匹配从i+1 到 j-1的区间转移过来。 否则在i 到 j 之间找与与i 匹配的k 进行转移。
#include<bits/stdc++.h>
using namespace std;
const int N=;
const int mod=1e9+;
int a[N],n;
long long f[N][N][][];
char s[N];
stack<int> st;
long long dp(int i,int j,int p,int q)
{
if(f[i][j][p][q]!=-) return f[i][j][p][q];
if(i+==j)
{
if((p== || q==) && (p!= || q!=)) return f[i][j][p][q]=;
else return f[i][j][p][q]=;
}
f[i][j][p][q]=;
if(a[i]==a[j])
{
if(p!= && q!= || p== && q==) return ;
for(int u=;u<=;u++)
for(int v=;v<=;v++)
if((u!=p || (!u && !p)) && (q!=v || (!q && !v)))
f[i][j][p][q]=(f[i][j][p][q]+dp(i+,j-,u,v))%mod;
}
else
{
for(int k=i+;k<j;k++)
{
if(a[k]!=a[i]) continue;
for(int u=;u<=;u++)
for(int v=;v<=;v++)
if(u!=v || (!u && !v))
f[i][j][p][q]=(f[i][j][p][q]+(dp(i,k,p,u)*dp(k+,j,v,q))%mod)%mod;
break;
}
}
return f[i][j][p][q];
}
int main()
{
memset(f,-,sizeof(f));
scanf("%s",s+);
n=strlen(s+);
int cnt=;
for(int i=;i<=n;i++)
{
if(s[i]=='(') st.push(i);
else
{
int cur=st.top();
cnt++; st.pop();
a[cur]=a[i]=cnt;
}
}
long long ans=dp(,n,,)+dp(,n,,)+dp(,n,,)+dp(,n,,)+dp(,n,,)+dp(,n,,)+dp(,n,,)+dp(,n,,)+dp(,n,,);
printf("%lld\n",ans%mod);
return ;
}
E - Multiplication Puzzle
题目大意:给你n个数字,每次取不是端点的一个数字a[ i ],总消耗加上a[ i-1 ]*a[ i ]*a[ i+1 ],直到最后剩两个数字,问你总消耗最少是多少。
思路:对于一个区间来说最后剩下的肯定是两端的数字,那么我们用dp[ i ][ j ]表示区间 i 到 j最小的消耗。枚举这个区间最后被取走的数进行状态转移。
dp[ i ][ j ]=min(dp[ i ][ j ] , dp[ i ][ k-1]+dp[ k+1 ][ j ]+a[ i ]*a[ j ]*a[ k ])
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
const int inf=0x3f3f3f3f;
int n,f[N][N],a[N];
int dp(int i,int j)
{
if(f[i][j]!=-) return f[i][j];
if(j-i<=) return ;
f[i][j]=inf;
for(int k=i+;k<=j-;k++)
f[i][j]=min(f[i][j],a[i]*a[k]*a[j]+dp(i,k)+dp(k,j));
return f[i][j];
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(f,-,sizeof(f));
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
printf("%d\n",dp(,n));
}
return ;
}
F - Food Delivery
题目大意:在x轴上有很多人同时点了外卖,给你他们的位置,再告诉你餐厅的位置,送外卖的人走1单位的长度 需要v秒,每个人等t秒 仇恨值就会增加 t * b[ i ],
让你求除最小的仇恨值。
思路:我们先将餐厅也作为一个点加入到点的集合中,按坐标的大小进行排序。
用dp[ i ][ j ][ 0 ]表示送完i 到 j的人,并最后在 i 的最小仇恨值, 用dp[ i ][ j ][ 1 ]表示送完i 到 j的人,并最后在 j 的最小仇恨值。
从餐厅的为止向外进行dp状态转移。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=;
const int inf=0x3f3f3f3f;
int dp[N][N][],n,v,pos,sum[N];
struct node
{
int x,b;
bool operator < (const node &rhs)const
{
return x<rhs.x;
}
}p[N];
int cal(int l,int r)
{
if(l>r) return ;
return sum[r]-sum[l-];
}
int main()
{
while(scanf("%d%d%d",&n,&v,&pos)!=EOF)
{
memset(dp,inf,sizeof(dp));
for(int i=;i<=n;i++)
scanf("%d%d",&p[i].x,&p[i].b);
n++; p[n].x=pos,p[n].b=;
sort(p+,p++n);
for(int i=;i<=n;i++)
{
if(p[i].x==pos)
{
pos=i;
break;
}
}
for(int i=;i<=n;i++)
sum[i]=sum[i-]+p[i].b;
dp[pos][pos][]=dp[pos][pos][]=;
for(int i=pos;i>=;i--)
{
for(int j=pos;j<=n;j++)
{
int daley=cal(,i-)+cal(j+,n);
if(i==j) continue;
dp[i][j][]=min(dp[i][j][],dp[i+][j][]+(p[i+].x-p[i].x)*(daley+p[i].b));
dp[i][j][]=min(dp[i][j][],dp[i+][j][]+(p[j].x-p[i].x)*(daley+p[i].b));
dp[i][j][]=min(dp[i][j][],dp[i][j-][]+(p[j].x-p[i].x)*(daley+p[j].b));
dp[i][j][]=min(dp[i][j][],dp[i][j-][]+(p[j].x-p[j-].x)*(daley+p[j].b));
}
}
printf("%d\n",min(dp[][n][],dp[][n][])*v);
}
return ;
}
G - You Are the One
题目大意:有n个排好队的人要上台表演,第k个人上台表演的消耗为( k-1 )*d[ k ]。 现在有一个栈,你可以暂时把人压入栈中,之后再出来,问你最小的消耗为多少。
思路:用dp[ i ][ j ]表示,从i个人开始上台,第j个人结束的最小消耗。
对于每个区间,我们枚举第i个人的出场顺序,那么区间就被分成了两个,这样来进行状态转移。
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=;
int f[N][N],n,sum[N],a[N];
int dp(int i,int j)
{
if(i>j) return ;
if(f[i][j]!=-) return f[i][j];
f[i][j]=inf;
for(int k=;k<=j-i+;k++)
{
f[i][j]=min(f[i][j],dp(i+,i+k-)+dp(i+k,j)+k*(sum[j]-sum[i+k-])+a[i]*(k-));
}
return f[i][j];
}
int main()
{
int T; scanf("%d",&T);
for(int cas=;cas<=T;cas++)
{
memset(f,-,sizeof(f));
memset(sum,,sizeof(sum));
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
for(int i=;i<=n;i++)
sum[i]=sum[i-]+a[i];
printf("Case #%d: %d\n",cas,dp(,n));
}
return ;
}
H - String painter
题目大意:给你两个由小写字母构成的字符串,你每次可以将第一个串的一个连续区间改成同一个小写字母,问你最少需要多少次改变,就能将第一个串变成第二个。
思路:直接将第一个串变成第二个非常困难, 我们先考虑一个空白的串变成第二个串,这样的问题区间dp就可以解决,然后通过这个对第一个串再进行一次dp就能求出答案。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=;
const int inf=0x3f3f3f3f;
int f[N][N],n,ans[N];
char a[N],b[N];
int dp(int i,int j)
{
if(f[i][j]!=-) return f[i][j];
if(i==j) return ;
if(i>j) return ;
f[i][j]=dp(i,j-)+;
for(int k=i;k<j;k++)
{
if(b[k]!=b[j]) continue;
f[i][j]=min(f[i][j],dp(i,k)+dp(k+,j-));
}
//printf("(%d,%d) %d\n",i,j,f[i][j]);
return f[i][j];
}
int main()
{
while(scanf("%s%s",a+,b+)==)
{
memset(f,-,sizeof(f));
memset(ans,,sizeof(ans));
int n=strlen(a+);
for(int i=;i<=n;i++) ans[i]=dp(,i);
for(int i=;i<=n;i++)
{
if(a[i]==b[i]) ans[i]=ans[i-];
else
{
for(int j=;j<i;j++)
ans[i]=min(ans[i],ans[j]+dp(j+,i));
}
}
printf("%d\n",ans[n]);
}
return ;
}
kuangbin 区间dp的更多相关文章
- 「kuangbin带你飞」专题二十二 区间DP
layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...
- [kuangbin带你飞]专题二十二 区间DP
ID Origin Title 17 / 60 Problem A ZOJ 3537 Cake 54 / 105 Problem B LightOJ 1422 Hallowee ...
- kuangbin专题十二 POJ3186 Treats for the Cows (区间dp)
Treats for the Cows Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7949 Accepted: 42 ...
- 【BZOJ-4380】Myjnie 区间DP
4380: [POI2015]Myjnie Time Limit: 40 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 162 Solved: ...
- 【POJ-1390】Blocks 区间DP
Blocks Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 5252 Accepted: 2165 Descriptio ...
- 区间DP LightOJ 1422 Halloween Costumes
http://lightoj.com/volume_showproblem.php?problem=1422 做的第一道区间DP的题目,试水. 参考解题报告: http://www.cnblogs.c ...
- BZOJ1055: [HAOI2008]玩具取名[区间DP]
1055: [HAOI2008]玩具取名 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1588 Solved: 925[Submit][Statu ...
- poj2955 Brackets (区间dp)
题目链接:http://poj.org/problem?id=2955 题意:给定字符串 求括号匹配最多时的子串长度. 区间dp,状态转移方程: dp[i][j]=max ( dp[i][j] , 2 ...
- HDU5900 QSC and Master(区间DP + 最小费用最大流)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5900 Description Every school has some legends, ...
随机推荐
- Python基础(函数部分)-day04
写在前面 上课第四天,打卡: 加勒比海盗今天上映:端午节公司发的粽子很有范! 一.函数的基本概念 - 函数是什么? 函数,就是一个'锤子',一个具有特定功能的'锤子',使用者可以在适当的时候使用这个 ...
- JAVA BufferedReader 类从标准输入读取数据
1,从标准输入上建立输入流: BufferedReader localReader = new BufferedReader( new InputStreamReader(System.in)); S ...
- wpc 双工
在控制台部署wcf双工 这个可以被silverlight 使用 <?xml version="1.0" encoding="utf-8" ?> &l ...
- wcf事务
wcf服务 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serial ...
- Linux - 进程服务资源
1.进程查看操作管理 ps -eaf # 查看所有进程 kill - PID # 强制终止某个PID进程 kill - PID # 安全退出 需程序内部处理信号 cmd & # 命令后台运行 ...
- Zabbix 监控服务
熟悉了解一些 zabbix 基础项目监控 zabbix_get 相关操作 :获取 item 监控数据 基本格式: -s --host: 指定客户端主机名或者IP -p --port:客户端端口,默认 ...
- char *a与char a[n]的区别
char *a='ab';//a[2]一定为'\0',但是,a[5]这样的指针越界不会报错 char a[3] = {'a','a','a'};//a[3]属于越界,会报错 char b[5]={'b ...
- 2018-2019-2 网络对抗技术 20165227 Exp5 MSF基础应用
2018-2019-2 网络对抗技术 20165227 Exp5 MSF基础应用 Exploit选取 主动攻击:ms17_010_eternalblue(成功) 浏览器攻击: ms10_042_hel ...
- 文件打包(.zip)并返回打压缩包存放路径
1.由于公司需要将一个或多个视频进行打包,格式如下图: 2.创建zipUtil工具包: package com.seegot.util; import java.io.BufferedOutputSt ...
- ditto复制增强
1.下载 http://ditto-cp.sourceforge.net/ 2.用法 ctrl+` ctrl+数字 或者 ctrl +` 然后用鼠标选择 soeasy