题意:有n杯调和果汁,用A,B,P三种果汁调,每一次可以往一个连续区间添加一种果汁,问最少需要加多少次。
n很大,最大10的五次方,但是状态数量很有限,只有7种,相同的果汁肯定要连续放才能使添加次数最少,而且连续相同的果汁不管有多少,总是跟一杯的时候结果相同,那么直接对于七种状态全排列找最优解就行了。
代码因为时间比较紧,写的比较挫一点,可以进一步优化。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
using namespace std;
map<string, int> s;
string rs[10];
map<string, int>::iterator p;
void init() {
s["A"] = 0;
rs[0] = "A";
s["AB"] = 1;
rs[1] = "AB";
rs[2] = "ABP";
rs[3] = "AP";
rs[4] = "B";
rs[5] = "BP";
rs[6] = "P";
s["ABP"] = 2;
s["AP"] = 3;
s["B"] = 4;
s["BP"] = 5;
s["P"] = 6;
}
int id[10];
vector<int> dx[10];
int main() {
init();
int n, i, j, k;
string a;
while(~scanf("%d", &n)) {
for(i = 0; i < 10; i++)
dx[i].clear();
for(i = 0; i < n; i++) {
cin >> a;
int b = s[a];
dx[b].push_back(i + 1);
}
int m = 0;
for(i = 0; i < 7; i++) {
if(dx[i].size()) {
id[m++] = i;
}
}
int ans = 100;
do {
int d = id[0];
int t = rs[d].size();
for(i = 1; i < m; i++) {
d = id[i];
for(j = 0; j < rs[d].size(); j++) {
for(k = 0; k < rs[id[i - 1]].size(); k++) {
if(rs[d][j] == rs[id[i - 1]][k])
break;
}
if(k == rs[id[i - 1]].size())
t++;
}
}
if(t < ans)
ans = t;
}while(next_permutation(id, id + m));
sort(id, id + m);
do {
int d = id[0];
int t = rs[d].size();
for(i = 1; i < m; i++) {
d = id[i];
for(j = 0; j < rs[d].size(); j++) {
for(k = 0; k < rs[id[i - 1]].size(); k++) {
if(rs[d][j] == rs[id[i - 1]][k])
break;
}
if(k == rs[id[i - 1]].size())
t++;
}
}
if(t == ans) {
int is = 0;
printf("%d\n", ans);
for(i = 0; i < m; i++) {
for(j = 0; j < dx[id[i]].size(); j++) {
if(is)
printf(" ");
else is = 1;
printf("%d", dx[id[i]][j]);
}
}
printf("\n");
break;
}
}while(next_permutation(id, id + m));
}
return 0;
}