zoukankan      html  css  js  c++  java
  • 【区间DP】低价回文

    【区间DP】低价回文

    标签(空格分隔): 区间DP 回文词


    【题目描述】

    追踪每头奶牛的去向是一件棘手的任务,为此农夫约翰安装了一套自动系统。他在每头牛身上安装了一个电子身份标签,当奶牛通过扫描器的时候,系统可以读取奶牛的身份信息。目前,每个身份都是由一个字符串组成的,长度为M (1≤M≤2000),所有的字符都取自小写的罗马字母。

    奶牛们都是顽皮的动物,有时她们会在通过扫描器的时候倒着走,这样一个原来身份为abcb的奶牛就可能有两个不同的身份了(abcb和bcba),而如果身份是abcba的话就不会有这个问题了。

    约翰想改变奶牛们的身份,使他们不管怎么走读起来都一样。比如说,abcb可以在最后加个a,变成回文abcba;也可以在前面加上bcb,变成回文bcbabcb;或者去除字母a,保留的bcb也是一条回文。总之,约翰可以在任意位置删除或插入一些字符使原字符串变成回文。

    不巧的是,身份标签是电子做的,每增加或删除一个字母都要付出相应的费用(0≤代价≤10000)。给定一头奶牛的身份标签和增加或删除相关字母的费用,找出把原来字符串变成回文的最小费用。注意空字符串也是回文。

    输入格式
    第一行:两个用空格分开的整数:N和M 第二行:一个长度恰好为M的字符串,代表初始的身份标签 第三行到第N+2行:每行为一个用空格分开的三元组:其中包括一个字符和两个整数,分别表示增加或删除这个字符的费用

    输出格式
    第一行:只有一个整数,表示改造这个身份标签的最小费用

    样例
    样例输入
    3 4
    abcb
    a 1000 1100
    b 350 700
    c 200 800

    样例输出
    900

    数据范围与提示
    如果在最后插入一个a,得到abcba,代价为1000;如果删除第一个a,得到bcb,代价为1100;如果在字符串的开头插入bcb,代价为350+200+350=900,这才是最优的做法

    【思路】

    这道题很恶心,不愧是学校题库的最后一题。线型DP和区间DP都是以回文词结尾,但是这两道思路完全不同,难度可想而知。
    对于一块新区间,要想保证区间中的元素是回文词,那就必须保证首元素和尾元素相同。如果相同,那么f[i][j]就能直接从f[i-1][j-1]转移过来,而且不用代价。如果不同,我们可以只处理首元素和尾元素中的一个。处理首元素,我们可以从f[i+1][j]转移过来,然后要么删除首元素,要么在尾端插入一个首元素。处理尾元素,我们可以从f[i][j-1]转移过来,同前。

    【代码】

    #include<cstring>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int maxn=2e5+5,INF=0x3f3f3f3f,maxe=2e3+5;
    int n,m,f[maxe][maxe],low[maxn],ans,del[maxn],add[maxn];
    inline int read(){
       int s=0,w=1;
       char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
       while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
       return s*w;
    }
    int main(){
    	m=read(),n=read();
    	char a[maxn];
    	cin>>a+1;
    	for(int i=1;i<=m;i++){
    		char x;
    		cin>>x;
    		cin>>add[x]>>del[x];
    	}//还是我没用快读时写的
    	memset(f,0x3f,sizeof(f));
    	for(int i=0;i<=n+1;i++)f[i][i]=0;//初始化
    	for(int d=2;d<=n;d++){
    		for(int i=1,j;(j=i+d-1)<=n;i++){
    			if(a[i]==a[j]){//相等
    				if(i==j-1)f[i][j]=0;//亲测必须加
    				f[i][j]=min(f[i][j],f[i+1][j-1]);
    			}
    			else f[i][j]=min(f[i+1][j]+min(del[a[i]],add[a[i]]),f[i][j-1]+min(del[a[j]],add[a[j]]));//不相等,要么在对a[i]删除或插入,要么对a[j]删除或插入
    		}
    	}
    	cout<<f[1][n];
    	return 0;
    }
    

    嘤嘤嘤 嘤嘤嘤 嘤嘤嘤嘤嘤

  • 相关阅读:
    软工实践寒假作业(1/2)
    java判断是否为数字
    前端测试工具Cypress
    StringBuffer&StringBuilder
    IO流
    kafka简介
    Python学习笔记10--unittest参数化
    python学习笔记9--日志模块logging
    Python学习笔记9-多线程和多进程
    python学习笔记9-单元测试unittest
  • 原文地址:https://www.cnblogs.com/614685877--aakennes/p/12859892.html
Copyright © 2011-2022 走看看