动态规划刷题记录1(不定期更新~)

Dp刷(chao)题记录&题(fu)解(zhi)

1.bzoj1055
[HAOI2008]玩具取名

题目大意:字典中有四个字母,’w’\’i’\’n’\’g’,给出每个字母的转换关系,即某个单个字母可以转换为两个字母。给出一个文本,求最初的可能文本(刚开始有且仅有一个字母)。

题解:明显是一道区间dp嘛~。设状态为文本[i,j]内的字母可以转化为字母[k],即f(i,j,k),要解状态的可能性。转移思路,自然是枚举i到j内的断点,再枚举关系。那么初始的状态转移方程就是

f[i][j][k]=f[i][x][pair(a)]==true
And f[x+1][j][pair(b)]==true ,其中pair(a)和pair(b)可以组合成k,而这个思路的时间复杂度是O(4
× len^3 × relation_number)。

//Kaiba_Seto 20170118
//orz cjkmao
#include <stdio.h>
#include <string.h>
#define RG register
#define __inline__ __attribute__((always_inline))
int n[5],t[5][17][3],len,f[205][205][5];
char ch[205],o[5]={‘W‘,‘I‘,‘N‘,‘G‘};
int rec(RG char c) {
  if(c==‘W‘)return 0;
  if(c==‘I‘)return 1;
  if(c==‘N‘)return 2;
  return 3; }
bool dfs(RG int x,RG int y,RG int k) {
  if(x == y)return ch[x] == o[k];
  if(~f[x][y][k])return f[x][y][k];
  for(RG int i=1;i<=n[k];i++)
    for(RG int j=x; j<y; j++)
      if(dfs(x,j,t[k][i][0]) && dfs(j+1,y,t[k][i][1]))
    return f[x][y][k]=1;
  return f[x][y][k]=0; }
int main() {
  memset(f,-1,sizeof(f));
  for(RG int i=0; i<4; i++)
    scanf("%d",&n[i]);
  for(RG int i=0; i<4; i++)
    for(RG int j=1; j<=n[i]; j++) {
      scanf("%s",ch);
      t[i][j][0]=rec(ch[0]);
      t[i][j][1]=rec(ch[1]); }
  scanf("%s",ch+1);
  len=strlen(ch+1);
  RG bool advanced=false;
  for(RG int k=0; k<4; k++)
    if(dfs(1,len,k))
      advanced=true,
    printf("%c",o[k]);
  puts(advanced?"":"The name is wrong!");
  return 0; }

2.bzoj1261 [SCOI2006]zh_tree

题目大意:张老师有一篇论文,有n个指标,每个指标在论文中出现的次数与论文指标出现总次数的比值成为指标的概率/频率,对指标序列1~n构建一颗树,令每个节点深度为r,规定根节点有r=0,记h=k(r+1)+c为访问点的代价,而f1*h1+f2*h2+...+fn*hn为树的平均代价,求树的最小平均代价。(题目给出的1~n的序列即为树的中序遍历)

题解:因为给定的序列是树的中序遍历,我们可以利用这个性质,树的问题转化为区间dp。令f[i][j]为区间[i,j]的最小代价,那么我们每次对一个区间选一个根节点,把左右区间分为左右子树就行,最后递归求解即可,深度处理的话,每层累计用前缀和优化一下就行了。

#include <stdio.h>
#include <string.h>
#define RG register
#define inf 1e6
#define dmin(a,b) ((a) < (b) ? (a) : (b))
int n;
bool vis[31][31];
double f[31][31],a[31],k,c;
double dfs(RG int x,RG int y) {
  if(x > y)return 0;
  if(vis[x][y])return f[x][y];
  f[x][y]=inf;
  vis[x][y]=true;
  for(RG int i=x; i<=y; i++)
    f[x][y]=dmin(f[x][y],dfs(x,i-1)+dfs(i+1,y)+c*
         (a[i]-a[i-1])/a[n]);
  return f[x][y]+=k*(a[y]-a[x-1])/a[n]; }
int main() {
  scanf("%d%lf%lf",&n,&k,&c);
  for(RG int i=1; i<=n; i++)
    scanf("%lf",&a[i]),a[i]+=a[i-1];
  printf("%0.3lf\n",dfs(1,n));
  return 0; }

3.bzoj1260 [CQOI2007]涂色paint

题目大意:给定一个长度为n的串,代表涂色目标,问最小涂色次数。涂色规则是,每次你可以将一个区间染成同一种颜色。

题解:用f[i][j]表示区间[i,j]变成目标区间的最少染色次数。下面考虑转移,因为可以发现,在我们递归处理任意区间[i,j]时,若要改动,将区间整段涂掉和小段小段涂是没差别的,所以最暴力的方法就是,我们每次选一种没改好的颜色直接整段涂掉就好,对每段没有涂好的再自己递归,最后求出最小值。但是我们还有更优的做法,更优的贪心策略显然是每次挑两个区间端点,端点颜色相同再整段涂掉,不同就再枚举断点递归求解就好了。考虑动态规划转移,初始态比较容易看出来,是f[i][i]=1,区间[i,j]转移的套路当然是[i+1,j]||[i,j-1][i+1,j-1]||f[i,k]+f[k+1,j]咯。

#include <stdio.h>
#include <string.h>
#define RG register
#define dmin(a,b) ((a) < (b) ? (a) : (b))
char ch[51];
int f[51][51],n;
int main() {
  memset(f,60,sizeof(f));
  scanf("%s",ch+1);
  n=strlen(ch+1);
  for(RG int i=1; i<=n; i++)
    f[i][i]=1;
  for(RG int l=1; l<n; l++)
    for(RG int i=1; i+l<=n; i++) {
      if(ch[i] == ch[i+l]) {
    if(l == 1)
      f[i][i+1]=1;
    else
      f[i][i+l]=dmin(dmin(f[i+1][i+l],f[i][i+l-1]),f[i+1][i+l-1]+1);
      }else
    for(RG int j=i; j<i+l; j++)
      f[i][i+l]=dmin(f[i][i+l],f[i][j]+f[j+1][i+l]); }
  printf("%d\n",f[1][n]);
  return 0; }

4.bzoj1048 [HAOI2007]分割矩阵

题目大意:分割矩阵(a,b)为n个矩形,求n个矩形内数值和的均方差。分割规则是每次用一条直线分割矩形为两个小块。

题解:设f[a][b][c][d][e]为矩形(a,b,c,d)分割e次的最小均方差,转移一下就行了

#include <math.h>
#include <stdio.h>
#include <string.h>
#define inf 1e9
#define RG register
#define sqr(a) ((a)*(a))
#define dmin(a,b) ((a) < (b) ? (a) : (b))
bool vis[11][11][11][11][11];
int n,m,k,a[11][11],sum[11][11];
double f[11][11][11][11][11],ave;
double dfs(RG int a,RG int b,RG int c,RG int d,RG int e) {
  double &ans=f[a][b][c][d][e];
  if(vis[a][b][c][d][e])
    return ans;
  vis[a][b][c][d][e]=1;
  if(!e) {
    ans=sum[b][d]-sum[a-1][d]-sum[b][c-1]+sum[a-1][c-1];
    return ans=sqr(ans-ave); }
  ans=inf;
  for(RG int i=a; i<b; i++)
    for(RG int j=0; j<e; j++)
      ans=dmin(ans,dfs(a,i,c,d,j)+dfs(i+1,b,c,d,e-j-1));
  for(RG int i=c; i<d; i++)
    for(RG int j=0; j<e; j++)
      ans=dmin(ans,dfs(a,b,c,i,j)+dfs(a,b,i+1,d,e-j-1));
  return ans; }
int main() {
  scanf("%d%d%d",&n,&m,&k);
  for(RG int i=1; i<=n; i++)
    for(RG int j=1; j<=m; j++)
      scanf("%d",&a[i][j]);
  for(RG int i=1; i<=n; i++)
    for(RG int j=1; j<=m; j++)
      sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
  ave=(double)sum[n][m]/k;
  printf("%0.2lf\n",sqrt(dfs(1,n,1,m,k-1)/k));
  return 0; }
时间: 2024-11-17 17:57:45

动态规划刷题记录1(不定期更新~)的相关文章

BZOJ 刷题记录 PART 4

[BZOJ1143]CTSC的题目...先用floyed传递闭包,然后直接上匈牙利算法. [BZOJ1452]从未写过的二维树状数组.好像很简单.. struct two_bit { int f[305][305]; inline void add(int x,int z,int A) { for (;x<=n;x+=L(x)) for (int y=z;y<=m;y+=L(y)) f[x][y]+=A; } inline int ask(int x,int z) { int ans=0; f

BZOJ 刷题记录 PART 1

作者 : Dolphin 原文地址:http://blog.csdn.net/qingdujun/article/details/27109035 一.实体完整性定义 [例1]将Student表中的Sno属性定义为码. CREATE TABLE Student ( Sno CHAR(10) PRIMARY KEY, /*在列定义主码*/ Sname CHAR(20) NOT NULL, Sage SMALLINT ); 或者: CREATE TABLE Student ( Sno CHAR(10

leetcode刷题记录(2)

301. Remove Invalid Parentheses Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results. Note: The input string may contain letters other than the parentheses ( and ). Examples: "()())()&q

暑期刷题记录

已经决定不玩空间了,在这里开一贴,用来记录暑假期间刷过的每一题. 时间从7.29号开始计算. 1. HDU 4883 TIANKENG’s restaurant    ( 贪心 ) 这个是bestcoder #2 的第一题,,居然想半天没有做出来,简直是太弱了,居然又在分情况讨论 题目大意:TIANKENG的饭店有客人陆续到达,如果再一批客人没有走的情况下,新来的客人就需要另外的座位,问最少需要多少座位. 题解: 贪心算法,首先对所有时间进行排序(时间相同以人数为第二关键字), 然后如果是到达,

Codeforces 刷题记录

Codeforces 每日刷题记录 打'+'是一些有启发意义的题目,部分附上一句话题解,每日更新3题,大部分题目较水. 1.+CF1073E:状压,数位dp,官方题解std骚操作 2.CF1072A 3.CF1072B 4.CF1072C 5.CF1068C:读题恶心 6.CF1073D:猜复杂度,模拟 7.CF1088A 8.CF1088B 9.CF1088C:构造思想 10.CF1066A 11.CF1066B 12.CF1066C 13.+CF1088E:推结论,tree dp,贪心 14

DP刷题记录

目录 dp刷题记录 codeforces 706C codeforces 940E BZOJ3997 POJ2279 GYM102082B GYM102082D codeforces132C L3-020 至多删三个字符 牛客 553C Chino with Queue POJ3260 The Fewest Coins Codeforces 372C dp刷题记录 codeforces 706C 题意:给出n个字符串,可以对每个字符串进行翻转操作, 每个操作对应一个消耗c[i],问经过操作后是否

CSP-S集训刷题记录

$ CSP.S $ 集训刷题记录: $ By~wcwcwch $ 一.字符串专题: 1. [模板]$ manacher $ 算法 模型:求出字符串 $ S $ 中所有回文串的位置及长度. 个人理解:解决这类问题,回文串的对称性质最重要. 于复杂度最关键的一句话: $ f[i]=min~(~r-i~,~f[~mid\times2-i~]~)~ $ (实现不同,边界可能不一样) 这个 $ min $ 函数左边 $ r-i $ 是当前位置到它所属于的回文串边界的距离,右边 $ mid\times 2

[2015.6.28] OI刷题记录

FZSZOJ刷题记录: 1051 砝码称重: DP 多重背包 1058 liqeuer: 序列DP 1061 挖地雷:DP,注意需要倒过来做DP,同时记录路径. 1059 Number:DP 1054 数塔问题:同数字三角形,普通DP 1390 等式问题:爆搜,枚举每个+号或-号的位置 1006 中位数:维护大根堆+小根堆,每次插入调整 1005 Cube Stacking:并查集维护当前在第几个和当前集合的高度,并查集变种. 1073 DNA分子的最佳比对:序列DP 1110 奖学金:傻逼题,

首师大附中科创教育平台 我的刷题记录(3)

首师大附中科创教育平台我的刷题记录(给大家刷11--15题吧) 仅供同学们参考,禁止抄袭!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #include<iostream> #include<math.h> using namespace std; int main() { int x,y; cin>>x; y=abs(x+2); cout<<x*x-y+5<<endl; return 0; } 绝对值函数 #include