BZOJ1080 劣质编码

23 篇文章 0 订阅
4 篇文章 0 订阅

非正解做法 , 时间不理想 , 轻喷……

建议先考虑二维的情形 , 训练指南上字符串那一章有类似题。
提示:
1. 怎么样简洁的表达一个状态呢? 其实用两个字符串就可以啦。
2. 怎么样转移一个状态 , 怎么样去掉避免重复 , 这是这个问题最让人头疼的地方。

详细解释在代码后:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <stack>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <cassert>

using namespace std;
const int maxn = 35;
const int INF = 0x3f3f3f3f;

int n;
char ss[maxn][60];
string s[maxn];

__inline string getBack(string& s1 , string& s3) 
{ return s1.substr(s3.size() , s1.size()-s3.size()); }

struct state
{
    string s1 , s2;
    state(){s1.clear(); s2.clear();}
    bool operator <(const state& b)const { return s1<b.s1 || (s1==b.s1 && s2<b.s2); }
    bool judge(string& s3)
    {
        if(s3.size()<=s1.size()) return s3==s1.substr(0 , s3.size());
        if(s3.size()<=s2.size()) return s3==s2.substr(0 , s3.size());
        return s2 == s3.substr(0 , s2.size());
    }
    state operator +(string& s3)
    {
        state res; 
        if(s3.size()<=s1.size())
        {
            res.s1 = getBack(s1, s3);
            res.s2 = getBack(s2, s3);
            return res;
        }
        if(s3.size()<=s2.size()) 
        {
            res.s1 = getBack(s3, s1);
            res.s2 = getBack(s2, s1);
            return res;
        }

        res.s1 = getBack(s2, s1);
        res.s2 = getBack(s3, s1);
        return res;
    }
};

map<state, int> dic;
queue<state> q;
int res = INF;
void update()
{
    while(!q.empty())
    {
        state now = q.front() , ne; q.pop();
        int step = dic[now];
        for(int i=1;i<=n;i++) 
        {
            if(!now.judge(s[i])) continue;
            ne = now+s[i];
            if(!dic.count(ne) || dic[ne]>step+s[i].size())
            {
                dic[ne] = step+s[i].size();
                q.push(ne);
            }
        }
    }
    if(dic.count(state())) res = min(res , dic[state()]);
}

bool getState(string s1 , string s2 , string s3 , int d)
{
    state now;
    if(s1.size()>s2.size()) swap(s1, s2); if(s1.size()>s3.size()) swap(s1, s3);
    if(s2.size()>s3.size()) swap(s2, s3);

    if(s1 != s2.substr(0 , s1.size())) return false;
    if(s2 != s3.substr(0 , s2.size())) return false;
    now.s1 = getBack(s2, s1);
    now.s2 = getBack(s3, s1);

    if(dic.count(now) && dic[now]<=d) return false;
    if(d+now.s2.size()*2-now.s1.size() >= res) return false; 
    dic[now] = d;
    q.push(now);
    return true;
}

map<string , int> all;
bool conbine(string s1 , string s2 , string& s3)
{
    if(s1.size()>s2.size()) swap(s1, s2);
    if(s2.substr(0 , s1.size())!=s1) return false;
    s3 = getBack(s2, s1);
    return true;
}

void solve(map<string , int>::iterator i)
{
    int step = i->second;
    for(int j=1;j<=n;j++) for(int k=j+1;k<=n;k++) 
    if(getState(s[j], s[k], i->first, (step+(step-i->first.size())/2)+s[j].size()+s[k].size())) update();

    for(int j=1;j<=n;j++) for(int k=j+1;k<=n;k++) 
    if(getState(i->first+s[j], i->first+s[k], "", (step+(step+i->first.size())/2)+s[j].size()+s[k].size())) update();
}

int main(int argc, char *argv[]) {

    scanf("%d" , &n);

    for(int i=0;i<=n;i++) gets(ss[i]);
    for(int i=1;i<=n;i++) for(int j=0;j<strlen(ss[i]);j++) if(isdigit(ss[i][j])) s[i]+= ss[i][j];

    for(int i=1;i<=n;i++) if(s[i].size()==0) { puts("0"); return 0; }

    for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) for(int k=j+1;k<=n;k++)
        if(getState(s[i], s[j], s[k], s[i].size()+s[j].size()+s[k].size())) update();

    queue<string> q;
    string nex;
    for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(conbine(s[i], s[j], nex))
    {
        q.push(nex);
        if(all.count(nex)==0 || all[nex]>s[i].size()+s[j].size())
        { 
            all[nex] = s[i].size()+s[j].size();
            solve(all.find(nex));
        }
    }


    while(!q.empty())
    {
        string now = q.front(); q.pop();
        int step = all[now];
        if(step>=res) continue;

        for(int i=1;i<=n;i++) if(conbine(now, s[i], nex))
            if(all.count(nex)==0 || all[nex]>step+s[i].size())
            {
                all[nex] = step+s[i].size();
                q.push(nex);

                solve(all.find(nex));
            }
    }


    if(res==INF) puts("-1");
    else printf("%d\n" , res/3);
    return 0;
}

空串直接特判。

解释:
1. 三种解码方式不能完全相同就有两种情形 , 要么一开始就不相同 , 否则就是一开始有两个相同 , 在某一个时刻变得不同。 绝对不可能三个一开始都相同。
2. 第一类情况好处理 , 一开始枚举是哪三个就可以。
3. 第二类情况我们需要先枚举二维的情况 , 也就是枚举两个一开始构造相同的解码方式的分界点 , 然后加上两个不同的串 , 这样状态就合法了。

时间刚好卡住 , 有没有好的优化方法呢? help

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

Fuxey

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值