非正解做法 , 时间不理想 , 轻喷……
建议先考虑二维的情形 , 训练指南上字符串那一章有类似题。
提示:
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