BZOJ1080 劣質編碼
阿新 • • 發佈:2018-12-31
非正解做法 , 時間不理想 , 輕噴……
建議先考慮二維的情形 , 訓練指南上字串那一章有類似題。
提示:
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