文章目录
bfs 多用于求最小步数(一个状态当作一步)或者最短路,换句话说就是该解是离根最近的,所以遇到的第一个解就可以break
dfs 用于搜索所有的解,且不用记录较多的信息就可以搜索全部的解
最小步数模型
1107. 魔板
样例输入:
2 6 8 4 5 7 3 1
样例输出:
7
BCABCCB
代码模板:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <queue>
using namespace std;
char g[2][4];
unordered_map<string, pair<char, string>> pre;
unordered_map<string, int> dist;
void set(string state)
{
for (int i = 0; i < 4; i ++ ) g[0][i] = state[i];
for (int i = 7, j = 0; j < 4; i --, j ++ ) g[1][j] = state[i];
}
string get()
{
string res;
for (int i = 0; i < 4; i ++ ) res += g[0][i];
for (int i = 3; i >= 0; i -- ) res += g[1][i];
return res;
}
string move0(string state)
{
set(state);
for (int i = 0; i < 4; i ++ ) swap(g[0][i], g[1][i]);
return get();
}
string move1(string state)
{
set(state);
int v0 = g[0][3], v1 = g[1][3];
for (int i = 3; i >= 0; i -- )
{
g[0][i] = g[0][i - 1];
g[1][i] = g[1][i - 1];
}
g[0][0] = v0, g[1][0] = v1;
return get();
}
string move2(string state)
{
set(state);
int v = g[0][1];
g[0][1] = g[1][1];
g[1][1] = g[1][2];
g[1][2] = g[0][2];
g[0][2] = v;
return get();
}
int bfs(string start, string end)
{
if (start == end) return 0;
queue<string> q;
q.push(start);
dist[start] = 0;
while (!q.empty())
{
auto t = q.front();
q.pop();
string m[3];
m[0] = move0(t);
m[1] = move1(t);
m[2] = move2(t);
for (int i = 0; i < 3; i ++ )
if (!dist.count(m[i]))
{
dist[m[i]] = dist[t] + 1;
pre[m[i]] = {'A' + i, t};
q.push(m[i]);
if (m[i] == end) return dist[end];
}
}
return -1;
}
int main()
{
int x;
string start, end;
for (int i = 0; i < 8; i ++ )
{
cin >> x;
end += char(x + '0');
}
for (int i = 1; i <= 8; i ++ ) start += char('0' + i);
int step = bfs(start, end);
cout << step << endl;
string res;
while (end != start)
{
res += pre[end].first;
end = pre[end].second;
}
reverse(res.begin(), res.end());
if (step > 0) cout << res << endl;
return 0;
}
双端队列广搜(边权只有0 or 1问题)
175. 电路维修
双端队列:
样例输入:
1
3 5
\\/\\
\\///
/\\\\
样例输出:
1
代码模板:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <deque>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 510, M = N * N;
int n, m;
char g[N][N];
int dist[N][N];
bool st[N][N];
int bfs()
{
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
dist[0][0] = 0;
deque<PII> q;
q.push_back({0, 0});
char cs[] = "\\/\\/"; //正确的连通方式
int dx[4] = {-1, -1, 1, 1}, dy[4] = {-1, 1, 1, -1};
int ix[4] = {-1, -1, 0, 0}, iy[4] = {-1, 0, 0, -1};
while (q.size())
{
PII t = q.front();
q.pop_front();
if (st[t.x][t.y]) continue;
st[t.x][t.y] = true;
for (int i = 0; i < 4; i ++ )
{
int a = t.x + dx[i], b = t.y + dy[i];
if (a < 0 || a > n || b < 0 || b > m) continue;
int ca = t.x + ix[i], cb = t.y + iy[i];
int d = dist[t.x][t.y] + (g[ca][cb] != cs[i]);
if (d < dist[a][b])
{
dist[a][b] = d;
if (g[ca][cb] != cs[i]) q.push_back({a, b}); //边权为1 插入队尾
else q.push_front({a, b}); //边权为 0 插入到队头
}
}
}
return dist[n][m];
}
int main()
{
int T;
scanf("%d", &T);
while (T -- )
{
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
int t = bfs();
if (t == 0x3f3f3f3f) puts("NO SOLUTION");
else printf("%d\n", t);
}
return 0;
}
双向BFS
190. 字串变换
样例输入:
abcd xyz
abc xu
ud y
y yz
样例输出:
3
代码模板:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <unordered_map>
using namespace std;
const int N = 6;
int n;
string A, B;
string a[N], b[N];
int extend(queue<string>& q, unordered_map<string, int>&da, unordered_map<string, int>& db,
string a[N], string b[N])
{
auto t = q.front();
q.pop();
for (int i = 0; i < n; i ++ ) //枚举规则
for (int j = 0; j < t.size(); j ++ ) //枚举字符串的位置
if (t.substr(j, a[i].size()) == a[i])
{
string r = t.substr(0, j) + b[i] + t.substr(j + a[i].size());//连接
if (db.count(r)) return da[t] + db[r] + 1; //会师
if (da.count(r)) continue; //重复continue
da[r] = da[t] + 1;
q.push(r);
}
return 11;
}
int bfs()
{
if (A == B) return 0;
queue<string> qa, qb;
unordered_map<string, int> da, db;
qa.push(A), qb.push(B);
da[A] = db[B] = 0;
int step = 0;
while (qa.size() && qb.size())
{
int t;
//小优化 :选择队列中元素数量少的一端扩展
if (qa.size() < qb.size()) t = extend(qa, da, db, a, b);
else t = extend(qb, db, da, b, a);
if (t <= 10) return t;
}
return 11;
}
int main()
{
cin >> A >> B;
while (cin >> a[n] >> b[n]) n ++ ;
int t = bfs();
if (t > 10) puts("NO ANSWER!");
else cout << t << endl;
return 0;
}
A*
179. 八数码
样例输入:
2 3 4 1 5 x 7 6 8
样例输出:
ullddrurdllurdruldr
代码模板:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, string> PIS;
//启发函数: 当前位置的数到正确位置的曼哈顿距离
int f(string state)
{
int res = 0;
for (int i = 0; i < 9; i ++ )
if (state[i] != 'x')
{
int v = state[i] - '1';
res += abs(v / 3 - i / 3) + abs(v % 3 - i % 3);
}
return res;
}
string bfs(string start)
{
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
char op[5] = "urdl";
string end = "12345678x"; //正确位置
unordered_map<string, int> dist;
unordered_map<string, pair<char, string>> pre; //记录路径
//小根堆:当前实际距离 + 当前位置的估计距离 杭电oj的八数码给忘了记一下
priority_queue<PIS, vector<PIS>, greater<PIS>> heap;
heap.push({f(start), start});
dist[start] = 0;
while(heap.size())
{
auto t = heap.top();
heap.pop();
string state = t.y;
if (state == end) break;
//找x的位置
int x, y;
for (int i = 0; i < 9; i ++ )
if (state[i] == 'x')
{
x = i / 3, y = i % 3;
break;
}
string source = state;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a < 0 || a >= 3 || b < 0 || b >= 3) continue;
state = source;
swap(state[x * 3 + y], state[a * 3 + b]);
if (dist.count(state) == 0 || dist[state] > dist[source] + 1)
{
dist[state] = dist[source] + 1;
pre[state] = {op[i], source};
heap.push({dist[state] + f(state), state}); //这里是当前真实距离 + 估计距离
}
}
}
string res;
while (end != start)
{
res += pre[end].x;
end = pre[end].y;
}
reverse(res.begin(), res.end());//
return res;
}
int main()
{
string start, seq;
char c;
while (cin >> c)
{
start += c;
if (c != 'x') seq += c;
}
int cnt = 0;
for (int i = 0; i < 8; i ++ )
for (int j = i + 1; j < 8; j ++ )
if (seq[i] > seq[j])
cnt ++ ;
if (cnt % 2) puts("unsolvable");
else cout << bfs(start) << endl;
return 0;
}
178. 第K短路
样例输入:
2 2
1 2 5
2 1 4
1 2 2
样例输出:
14
代码模板:
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
const int N = 1010, M = 200010;
int n, m, S, T, K;
int h[N], rh[N], e[M], w[M], ne[M], idx;
int dist[N], cnt[N];
bool st[N];
void add(int h[], int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void dijkstra()
{
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, T});
memset(dist, 0x3f, sizeof dist);
dist[T] = 0;
while (heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.y;
if (st[ver]) continue;
st[ver] = true;
for (int i = rh[ver]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
heap.push({dist[j], j});
}
}
}
}
int astar()
{
//当前实际位置 + 估计距离 // 当前实即距离 // 元素
//小根堆
priority_queue<PIII, vector<PIII>, greater<PIII>> heap;
heap.push({dist[S], {0, S}});
while (heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.y.y, distance = t.y.x;
cnt[ver] ++ ;
if (cnt[T] == K) return distance;
for (int i = h[ver]; ~i; i = ne[i])
{
int j = e[i];
if (cnt[j] < K) //把所有能扩展到的点都加进队列,来求第k最短路
heap.push({distance + w[i] + dist[j], {distance + w[i], j}});
}
}
return -1;
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
memset(rh, -1, sizeof rh);
for (int i = 0; i < m; i ++ )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
//tip: 有向图分别存储正向和反向
add(h, a, b, c);
add(rh, b, a, c);
}
scanf("%d%d%d", &S, &T, &K);
if (S == T) K ++ ;
//预处理估价函数: 当前位置到终点的距离
dijkstra();
//A*
printf("%d\n", astar());
return 0;
}
dfs之搜索顺序
1117. 单词接龙
样例输入:
5
at
touch
cheat
choose
tact
a
样例输出:
23
代码模板:
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 21;
int n;
string word[N];
int g[N][N];
int used[N];
int ans;
void dfs(string dragon, int last)
{
ans = max((int)dragon.size(), ans);
used[last] ++ ;
for (int i = 0; i < n; i ++ )
if (g[last][i] && used[i] < 2)
dfs(dragon + word[i].substr(g[last][i]), i);
used[last] -- ;
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> word[i];
char start;
cin >> start;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
{
string a = word[i], b = word[j];
for (int k = 1; k < min(a.size(), b.size()); k ++ )
if (a.substr(a.size() - k, k) == b.substr(0, k))
{
g[i][j] = k;
break;
}
}
for (int i = 0; i < n; i ++ )
if (word[i][0] == start)
dfs(word[i], i);
cout << ans << endl;
return 0;
}
1118. 分成互质组
样例输入:
6
14 20 33 117 143 175
样例输出:
3
代码模板:
#include <iostream>
using namespace std;
const int N = 15;
int n;
int p[N]; // 存放数
int group[N][N]; // 存放每个组
bool st[N]; // 标记每个数是否被放进了组内
int ans; // 当前所存在的最优解
int gcd(int a, int b) { // gcd求最大公约数
return b ? gcd(b, a % b) : a;
}
bool check(int g[], int gc, int num) { // 判断当前组中的数是否和该数都互质(即该数能否放进该组)
for (int i = 0; i < gc; ++ i) // 枚举此组组内每个数
if (gcd(g[i], p[num]) > 1 ) // 只要组内有数和该数不互质了就 return false
return false;
return true; // 否则 return true
}
//1、放进此时的最后一个组内
//2、新开一个组放该数
void dfs(int g, int gc, int tc, int start) {
// g为当前的最后一组的组的序号, gc为当前组内搜索到的数的序号;
// tc为当前搜索过的数的数量, start为当前组开始搜索的数的序号
if (g >= ans) return ; // 如果有比当前最优解所需的组数更多的解法说明此解不为最优解-->直接return即可
if (tc == n) ans = g; // 如果搜完了所有点了,说明此解为当前的最优解,更新最优解
bool flag = true; // flag标记是否能新开一组
for (int i = start; i < n; ++ i) // 枚举每个数
if (!st[i] && check(group[g], gc, i)) { // 如果当前数还未被放进组里 且 与当前的组中的数都互质
st[i] = true; // 将该数标记为被放进组里的状态
group[g][gc] = p[i]; // 将该数放进该组
dfs(g, gc + 1, tc + 1, i + 1);
// 继续搜索该组,组内数的数量gc + 1,总的数的数量tc + 1,搜索的数的序号i + 1
st[i] = false; // 恢复
flag = false; // 如果能放进当前最后一组,则不用新开一组,故flag标记为false
}
if (flag) dfs(g + 1, 0, tc, 0);
// 如果无法放进最后一组,则新开一组来搜索
// 当前最后一组的组的序号g + 1, 组内搜索的数的序号gc为0;
// 搜索到的数tc未变, 当前组内开始搜索的数的序号start为0
/* 此时的dfs操作其实就相当于开了一个组开始搜索的操作,还没有放数进来 */
}
int main() {
cin >> n;
ans = n; // 还未搜索时,假定最优解为最坏的情况每个数都分一组
for (int i = 0; i < n; ++ i) scanf("%d", p + i);
dfs(1, 0, 0, 0);
// 从第一个组g = 1, 组内没有数gc = 0;
// 还没搜索到点tc = 0, 当前组还未开始遍历数start = 0的初始状态开始搜索
cout << ans << endl; // 输出搜索完后的最优解
return 0;
}
dfs之剪枝与优化
166. 数独
样例输入:
4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end
样例输出:
417369825632158947958724316825437169791586432346912758289643571573291684164875293
416837529982465371735129468571298643293746185864351297647913852359682714128574936
代码模板:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 9;
int lowbit(int x){
return x&(-x);
}
int col[N],row[N],cell[N][N];
char str[90];
int map[1<<N],ones[1<<N];
void init(){
//将行和列和方格中得状态都设为可填状态 0为不可填 1为可填
for(int i=0;i<N;i++) col[i]=row[i]=(1<<N)-1;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
cell[i][j]=(1<<N)-1;
}
int getones(int x,int y){
//活得行列方格中所有1(可填)的交集
return col[y]&row[x]&cell[x/3][y/3];
}
bool dfs(int cnt){
if(!cnt) return true;
//找到可填充元素最少的位置 -> 优化搜索顺序
int minn=10,x,y;
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
if(ones[getones(i,j)]<minn&&str[i*9+j]=='.'){
minn=ones[getones(i,j)];
x=i,y=j;
}
//开始填充数字
for(int i=getones(x,y);i;i-=lowbit(i)){ //枚举所有1(可填)
int t=map[lowbit(i)]; //获得低位1的十进制数 map获得低位1的位置
row[x]-=(1<<t);
col[y]-=(1<<t);
cell[x/3][y/3]-=(1<<t);
str[x*9+y]='1'+t;
if(dfs(cnt-1)) return true;
//回溯
row[x]+=(1<<t);
col[y]+=(1<<t);
cell[x/3][y/3]+=(1<<t);
str[x*9+y]='.';
}
return false;
}
int main(){
//预处理某状态是第几位
for(int i=0;i<N;i++) map[1<<i]=i;
//预处理所有状态为1(可填)的个数
for(int i=0;i<1<<N;i++){
int s=0;
for(int j=i;j;j-=lowbit(j)) s++;
ones[i]=s;
}
while(cin>>str,str[0]!='e'){
init(); //初始化
int cnt=N*N;
//将题目中已经填得数字初始化行列方格
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
if(str[i*9+j]!='.'){
int t=str[i*9+j]-'1';
row[i]-=1<<t;
col[j]-=1<<t;
cell[i/3][j/3]-=1<<t;
cnt--; //填方格-1
}
dfs(cnt);
cout<<str<<endl;
}
return 0;
}
167. 木棒
样例输入:
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
样例输出:
6
5
代码模板:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 64;
int n,sum,length;
int sticks[N];
bool st[N];
//u当前已经有多少根木棒 cur当前木棒的长度 start当前从哪根木棍开始枚举(木棍从大到小枚举)
bool dfs(int u,int cur,int start){
//当前的木棒数量等于所有木棍的总和->当前木棒长度可行
if(u*length==sum) return true;
//当前的木棒长度可行 开始递归下一根木棒
if(cur==length) return dfs(u+1,0,0);
//从大到小枚举木棍
for(int i=start;i<n;i++){
if(st[i]) continue;
int l=sticks[i];
if(cur+l>length) continue;
st[i]=true;
if(dfs(u,cur+l,i+1)) return true;
st[i]=false;
//如果是木棒的第一个木棍失败,则一定失败
if(!cur) return false;
//如果是该木棒的最后一根木棒时失败时,说明前面的排法方案有问题,直接return
if(cur+l==length) return false;
// 跳过相同的木棒
int j=i;
while(j<n && sticks[j]==l) j++;
i=j-1;
}
return false;
}
int main(){
while(cin>>n,n){
sum=0,length=0;
for(int i=0;i<n;i++){
int l;
cin>>l;
sticks[i]=l;
sum+=l;
length=max(length,l);
}
//降序排序->优化搜索顺序->排除等效冗余
sort(sticks,sticks+n);
reverse(sticks,sticks+n);
memset(st,false,sizeof st);
for(int i=0;i<n;i++)
if(sticks[i]>50)
st[i]=true;
while(true){
//枚举的木棒的长度必须被sum整除
if(sum%length==0&&dfs(0,0,0)){
cout<<length<<endl;
break;
}
length++;
}
}
return 0;
}
168. 生日蛋糕
思路:
1.首先看到题目知道暴搜,暴力枚举r和h,由于体积公式中r的影响最大所以先枚举r再枚举h,但是r和h有范围 最小:当前层数;最大 (1)剩下的体积根据公式当高等于1时候r取得最大值 (2) 下一层的半径+1。
2.当剩下的体积小于可安排的最小体积,return;当前表面积加上可安排的最小表面积大于ans,return;
3.根据表面积和体积公式求得关系剪枝:当前已经安排表面积得加上(…大于)ans,return(最恶心且最重要得一环)
样例输入:
100
2
样例输出:
68
代码模板:
#include <bits/stdc++.h>
using namespace std;
const int M = 30;
int n, m, ans = 0x3f3f3f3f;
int minv[M], mins[M], R[M], H[M];
//自底向上递归
//v当前处理的体积和 s当前处理的面积和
void dfs(int dep, int v, int s)
{
if (v + minv[dep] > n) return;
if (s + mins[dep] >= ans) return; // 剪枝(4)
if (s + 2 * (n - v) / R[dep + 1] >= ans) return; // 剪枝(5)
if(dep == 0)
{
if (v == n) ans = min(ans, s);
return;
}
// 剪枝(2)(3)
for (int r = min(R[dep + 1] - 1, (int)sqrt(n - v)); r >= dep; r -- )
for (int h = min(H[dep + 1] - 1, (n - v) / r / r); h >= dep; h -- )
{
R[dep] = r, H[dep] = h;
dfs(dep - 1, v + r * r * h, s + 2 * r * h + (dep == m ? r * r : 0));
}
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i ++ )
{
minv[i] = minv[i - 1] + i * i * i;
mins[i] = mins[i - 1] + 2 * i * i;
}
R[m + 1] = H[m + 1] = 0x3f3f3f3f;
dfs(m, 0, 0); // 剪枝(1)
if (ans == 0x3f3f3f3f) puts("0");
else printf("%d\n", ans);
return 0;
}
迭代加深
170.加成序列
样例输入:
5
7
12
15
77
0
样例输出:
1 2 4 5
1 2 4 6 7
1 2 4 8 12
1 2 4 5 10 15
1 2 4 8 9 17 34 68 77
代码模板:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110;
int n;
int path[N];
bool dfs(int u, int k)
{
if (u == k) return path[u - 1] == n;
bool st[N] = {0}; //排除等效冗余 两个数相加有重复数的可能
for (int i = u - 1; i >= 0; i -- ) //优化搜索顺序 优先从大到小枚举
for (int j = i; j >= 0; j -- )
{
int s = path[i] + path[j];
if (s > n || s <= path[u - 1] || st[s]) continue;
st[s] = true;
path[u] = s;
if (dfs(u + 1, k)) return true;
}
return false;
}
int main()
{
path[0] = 1;
while (cin >> n, n)
{
int k = 1;
while (!dfs(1, k)) k ++ ;
for (int i = 0; i < k; i ++ ) cout << path[i] << ' ';
cout << endl;
}
return 0;
}
双向DFS
171.送礼物(dfs排序+二分)
样例输入:
20 5
7
5
4
18
1
样例输出:
19
代码模板:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N = 1<<24;
int w,n,g[N];
int weight[N],k,cnt;
int ans;
void dfs(int u,int s){
if(u==k){
weight[cnt++]=s;
return;
}
if((LL)s+g[u]<=w) dfs(u+1,s+g[u]);
dfs(u+1,s);
}
void dfs2(int u,int s){
if(u==n){
int l=0,r=cnt-1;
while(l<r){
int mid=l+r+1>>1;
if(weight[mid]+(LL)s>w) r=mid-1;
else l=mid;
}
if((LL)s+weight[r]<=w) ans=max(ans,weight[r]+s);
return;
}
if((LL)s+g[u]<=w) dfs2(u+1,s+g[u]);
dfs2(u+1,s);
}
int main(){
cin>>w>>n;
for(int i=0;i<n;i++) cin>>g[i];
sort(g,g+n);
reverse(g,g+n);
k=n/2+2;
dfs(0,0);
sort(weight,weight+cnt);
int t=1;
for(int i=1;i<cnt;i++)
if(weight[i]!=weight[i-1])
weight[t++]=weight[i];
cnt=t;
dfs2(k,0);
cout<<ans<<endl;
return 0;
}
IDA*
IDA* + 迭代加深
当前深度 + 估价函数 > 深度限制 —> return;
180. 排书
样例输入:
3
6
1 3 4 6 2 5
5
5 4 3 2 1
10
6 8 5 3 4 7 2 9 1 10
样例输出:
2
3
5 or more
代码模板:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 15;
int n;
int q[N], w[5][N];
int f() //估价函数
{
int res = 0;
for (int i = 0; i + 1 < n; i ++ )
if (q[i + 1] != q[i] + 1)
res ++ ;
return (res + 2) / 3;
}
bool check()
{
for (int i = 0; i < n; i ++ )
if (q[i] != i + 1)
return false;
return true;
}
//depth当前深度 max_depth最大深度
bool dfs(int depth, int max_depth)
{
if (depth + f() > max_depth) return false; //当前深度加上估价函数
if (check()) return true; //是否升序
for (int l = 0; l < n; l ++ )
for (int r = l; r < n; r ++ )
for (int k = r + 1; k < n; k ++ )
{
//备份
memcpy(w[depth], q, sizeof q);
int x, y;
//位置交换
for (x = r + 1, y = l; x <= k; x ++, y ++ ) q[y] = w[depth][x];
for (x = l; x <= r; x ++, y ++ ) q[y] = w[depth][x];
if (dfs(depth + 1, max_depth)) return true;
memcpy(q, w[depth], sizeof q); //恢复现场
}
return false;
}
int main()
{
int T;
scanf("%d", &T);
while (T -- )
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
int depth = 0;
//迭代加深
while (depth < 5 && !dfs(0, depth)) depth ++ ;
if (depth >= 5) puts("5 or more");
else printf("%d\n", depth);
}
return 0;
}
181. 回转游戏
样例输入:
1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0
样例输出:
AC
2
DDHH
2
代码模板:
/*
0 1
2 3
4 5 6 7 8 9 10
11 12
13 14 15 16 17 18 19
20 21
22 23
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 24;
int q[N];
int op[8][7] = {
{0, 2, 6, 11, 15, 20, 22},
{1, 3, 8, 12, 17, 21, 23},
{10, 9, 8, 7, 6, 5, 4},
{19, 18, 17, 16, 15, 14, 13},
{23, 21, 17, 12, 8, 3, 1},
{22, 20, 15, 11, 6, 2, 0},
{13, 14, 15, 16, 17, 18, 19},
{4, 5, 6, 7, 8, 9, 10}
};
int center[8] = {6, 7, 8, 11, 12, 15, 16, 17};
int opposite[8] = {5, 4, 7, 6, 1, 0, 3, 2};
int path[100];
int f()
{
static int sum[4];
memset(sum, 0, sizeof sum);
for (int i = 0; i < 8; i ++ ) sum[q[center[i]]] ++ ;
int s = 0;
for (int i = 1; i <= 3; i ++ ) s = max(s, sum[i]);
return 8 - s;
}
bool check()
{
for (int i = 1; i < 8; i ++ )
if (q[center[i]] != q[center[0]])
return false;
return true;
}
void operation(int x)
{
int t = q[op[x][0]];
for (int i = 0; i < 6; i ++ ) q[op[x][i]] = q[op[x][i + 1]];
q[op[x][6]] = t;
}
bool dfs(int depth, int max_depth, int last)
{
if (depth + f() > max_depth) return false;
if (check()) return true;
for (int i = 0; i < 8; i ++ )
{
if (opposite[i] == last) continue;
operation(i);
path[depth] = i;
if (dfs(depth + 1, max_depth, i)) return true;
operation(opposite[i]);
}
return false;
}
int main()
{
while (scanf("%d", &q[0]), q[0])
{
for (int i = 1; i < N; i ++ ) scanf("%d", &q[i]);
int depth = 0;
while (!dfs(0, depth, -1)) depth ++ ;
if (!depth) printf("No moves needed");
for (int i = 0; i < depth; i ++ ) printf("%c", 'A' + path[i]);
printf("\n%d\n", q[6]);
}
return 0;
}