zoukankan      html  css  js  c++  java
  • 回文相关

    考虑对于一个确定的字符串,判断其是否回文,可以

    直接hash,那么多事干嘛

    那么对于一个非回文的字符串,欲使其回文,求使其回文付出的最小代价?

    可以删,可以增?

    LuoguP1435 (没给出长度)

    LuoguT16647 (已经给出长度)

    本题中,仅支持

    • 插入

    最开始打了个搜索,非常垃圾并没有搜对。

    正解是DP。

    一个回文串[l,r]中[l+1,r-1]一定也是回文串,长的回文可以由短的回文推出

    f[i][j] 表示使[i,j]成为回文串付出的代价。

    f[i][j] = ( f[i+1][j-1] ) ( s[i]==s[j] )

    f[i][j] = min ( f[i+1][j] , f[i][j-1] ) ( s[i]!=s[j] )

    接下来考虑如何枚举 i j ,我们可以依次枚举 回文长度len 左端点 i ,再由leni计算出j

    #include<iostream>
    #include<cstring>
    #include<string>
    using namespace std;
    #define j i+len-1//计算右端点
    
    int n;
    string s;
    int f[5002][5002];
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin>>n>>s;
        s=" "+s;
        for(int i=1;i<n;i++)
            f[i][i+1]=(s[i]==s[i+1]?0:1);//预处理,一个字符和它后面的字符不同,那么这两个字符回文的代价就为1
        for(int len=3;len<=n;len++)//枚举长度
            for(int i=1;i<=n-len+1;i++)//枚举起点
                if(s[i]==s[j])
                    f[i][j]=f[i+1][j-1];
                else
                    f[i][j]=min(f[i+1][j],f[i][j-1])+1;
        cout<<f[1][n];
        return 0;
    }
    

    或者直接枚举i j

    #include<iostream>
    #include<cstring>
    #include<string>
    using namespace std;
    
    int n;
    string s;
    int f[5002][5002];
    
    int main()
    {
    	ios::sync_with_stdio(0);
    	cin>>n>>s;
    	s=" "+s;
    	for(int i=1;i<n;i++)
    		f[i][i+1]=(s[i]==s[i+1]?0:1);
    	/*for(int i=n;i;i--)
    		for(int j=i+1;j<=n;j++)这样也是可以的*/
      	for(int j=2;j<=n;j++)
    		for(int i=j-1;i;i--)
    			if(s[i]==s[j])
    				f[i][j]=f[i+1][j-1];
    			else
    				f[i][j]=min(f[i+1][j],f[i][j-1])+1;
    	cout<<f[1][n];
    	return 0;
    }
    

    注意,这里枚举不能

    for(int i=1;i<=n;i++)
      for(int j=i+1;j<=n;j++)
    

    因为i j的状态需要从i+1 i j-1 j得来,必须从中间向两边枚举


    考虑增加操作

    • 增加
    • 删除

    每种、每次操作又都有不同的代价。考虑代价最小?

    LuoguP2890

    字串S长M,由N个小写字母构成。欲通过增删字母将其变为回文串,增删特定字母花费不同,求最小花费。

    其实和上面还是一样,但是在转移时有了更多的选择

    s[i]与s[j]相同,直接从i+1 j-1转移过来

    从i j-1转移过来,取添加或删除字符j的最小代价

    从i+1 j转移过来,取添加或删除字符i的最小代价

    关于i j的枚举,仍可以枚举长度、i 再算出j

    或者直接枚举i j

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int add[200],del[200],f[2001][2001];//add[]增加字符的代价,del[]删除字符的代价
    int main()
    {
        ios::sync_with_stdio(false);
        int n,m;
        cin>>n>>m;
        string s;
        cin>>s;
        s=' '+s;
        for(int i=0;i<n;i++)
        {
            char c;
            cin>>c;
            cin>>add[(int)c]>>del[(int)c];
        }
        for(int r=2;r<=m;r++)
            for(int l=r-1;l;l--)
            {
                if(s[l]==s[r])
                    f[l][r]=f[l+1][r-1];
                else//这里也可以改一下然后把括号去掉
                {
                    int a1=f[l][r-1]+min(del[(int)s[r]],add[(int)s[r]]);
                    int a2=f[l+1][r]+min(del[(int)s[l]],add[(int)s[l]]);
                    f[l][r]=min(a1,a2);
                }
            }
        cout<<f[1][m];
        return 0;
    }
    

    我写这么艰难还是因为我不会DP

  • 相关阅读:
    Fish
    Brackets
    StoneWall【★★★★★】
    Nesting
    ajax补充FormData
    初始Ajax
    extra过滤
    Django 之缓存
    django中的信号
    Form组件归类
  • 原文地址:https://www.cnblogs.com/syhien/p/7805816.html
Copyright © 2011-2022 走看看