1八皇后类型
模板
1判断边界
2剪枝
3尝试放入并判断,
4标记,最后回溯 (3 4两步可以调换)
#include<bits/stdc++.h>
using namespace std;
int A[10000000]={0};
int n;
int tot=0;
void search(int cur){
if(cur == n) {//判断边界
tot++;//当cur等于行数,那么就代表摆放成功
if(tot<=3){
for(int i=0;i<n;i++){
if(i)cout<<" ";
cout<<A[i];
}
cout<<endl;
}
return;
}
else for(int i=0;i<n;i++)
{
int ok = 1;
A[cur] = i+1;//尝试把第cur行的皇后放入第i列
for(int j=0;j<cur;j++)
{
if(A[cur]==A[j]||cur-A[cur]==j-A[j]||cur+A[cur]==j+A[j])//判断是否同列同主对角线和同副对角线
{
ok = 0; break;//如果是,则不递归并退循环,回溯
}
}
if(ok) search(cur+1);//如果合法,则递归
}
}
int main(){
cin>>n;
search(0);
cout<<tot;
}
奇怪的电梯
#include<bits/stdc++.h>
using namespace std;
int r[100000]={0};
int s[100000]={0};
int n,a,b;
int sum=100000000;
void dfs(int cur,int click){
if(cur==b){//1判断边界
if(click<sum)sum=click;
return;
}
if(cur>b||cur<1)return;
if(click>sum)return;//剪枝
r[cur]=1;//标记,像此类操作少的,可以统一进行标记回溯.
if(cur+s[cur]<=n&&!r[cur+s[cur]])
dfs(cur+s[cur],click+1);
if(cur-s[cur]>=1&&!r[cur-s[cur]])
dfs(cur-s[cur],click+1);
r[cur]=0;//回溯
}
int main(){
cin>>n>>a>>b;
for(int i=1;i<=n;i++)cin>>s[i];
dfs(a,0);
if(sum!=100000000){
cout<<sum;
}else cout<<"-1";
}
bfs版本:
#include<bits/stdc++.h>
using namespace std;
struct node{
int cur;
int step;
node(int cur,int step):cur(cur),step(step){
}
node():cur(0),step(0){
}
};
queue<node> q;
int n,a,b;
int s[1000000]={0};
int vis[1000000]={0};
node t;
int main(){
cin>>n>>a>>b;
for(int i=1;i<=n;i++)cin>>s[i];
q.push(node(a,0));
while(!q.empty()){
t=q.front();
q.pop();
if(t.cur==b){
break;
}
if(t.cur+s[t.cur]<=b&&!vis[t.cur+s[t.cur]]){
q.push(node(t.cur+s[t.cur],t.step+1));
vis[t.cur+s[t.cur]]=1;//bfs不用回溯,求的是最短路,只能到当前节点一次
}
if(t.cur-s[t.cur]>=1&&!vis[t.cur-s[t.cur]]){
q.push(node(t.cur-s[t.cur],t.step+1));
vis[t.cur-s[t.cur]]=1;
}
}
if(t.cur==b)cout<<t.step;
else cout<<"-1";
}
/*
总结bfs:
1压入队头
2取队头
3判断
4遍历压入,标记vis
*/
单词接龙
#include<bits/stdc++.h>
using namespace std;
string str[20];
int use[20], length = 0, n;
int canlink(string str1, string str2) {
for(int i = 1; i < min(str1.length(), str2.length()); i++) {//重叠长度从1开始,直到最短的字符串长度-1(因为不能包含)
int flag = 1;
for(int j = 0; j < i; j++)
if(str1[str1.length() - i + j] != str2[j]) flag = 0;//逐个检测是否相等
if(flag) return i;//检测完毕相等则立即return
}
return 0;//无重叠部分,返回0
}
void solve(string strnow, int lengthnow,int cur) {
if(cur>2*n)return;
length = max(lengthnow, length);//更新最大长度
for(int i = 0; i < n; i++) {
if(use[i] >= 2) continue;//该字符串使用次数需要小于2
int c = canlink(strnow, str[i]);//获取重叠长度
if(c > 0) {//有重叠部分就开始dfs
use[i]++;
solve(str[i], lengthnow + str[i].length() - c,cur+1);
use[i]--;
}
}
}
main() {
cin >> n;
for(int i = 0; i <= n; i++) use[i] = 0, cin >> str[i];//str[n]为开始字符
solve(' '+str[n], 1,0);//有必要解释一下开始阶段。为了指定第一个字符,而且因为canlink需要重叠部分小于最短长度-1,所以要从前面添加一个无意义充长度的‘ ’。这样就强制了canlink函数比较最后一位。
cout << length ;
}
选数字
#include<bits/stdc++.h>
using namespace std;
int n,k;
int a[1000000]={0};
int vis[100000]={0};
int sum=0;
void dfs(long long int l,int cur,int cnt){
if(cur==k){//边界
int i;
for(i=2;i<=l;i++){
if(l%i==0){
break;
}
}
if(l==i){
sum++;
}
return;
}
if(cur>k)return;//剪枝
for(int i=cnt;i<n;i++){
if(!vis[i]){//判断
l+=a[i];
vis[i]=1;//标记
dfs(l,cur+1,i+1);
l-=a[i];
vis[i]=0;//回溯
}
}
}
int main(){
cin>>n>>k;
for(int i=0;i<n;i++)cin>>a[i];
dfs(0,0,0);
cout<<sum;
}
考前临时抱佛jiao
#include<bits/stdc++.h>
using namespace std;
int a[4][25]={0};
int s[4]={0};
int m,ans=0;
int l,r;
void dfs(int x,int y){
if(y>s[x]){//边界
m=min(m,max(l,r));//取左右脑最长的时间,m又要尽量小
return;
}
//尝试往左右脑放题目;
l+=a[x][y];
dfs(x,y+1);
l-=a[x][y];
r+=a[x][y];
dfs(x,y+1);
r-=a[x][y];
}
int main(){
cin>>s[0]>>s[1]>>s[2]>>s[3];
for(int i=0;i<4;i++){
for(int j=0;j<s[i];j++){
cin>>a[i][j];
}
}
for(int i=0;i<4;i++){
m=10000000;
l=r=0;
dfs(i,0);
ans+=m;
}
cout<<ans;
}