今天发现了一个函数
next_permutation(a,a+n)
即求当前排列的下n个排列
例如n=1 对1234用 求出1243
在全排列问题中很有效

火星人这道题就是说 求一个全排列之下的第n个排列
正常也可以dfs写 只需要res到m+1时输出就行了 并且注意要剪枝

[p1088火星人] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[10100];
int main()
{
cin>>n;
cin>>m;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<m;i++)
{
next_permutation(a,a+n);
}
for(int i=0;i<n;i++) cout<<a[i]<<" ";
return 0;
}

烤鸡这道题要先输出方案数 所以要特别做法 用一个二维数组存
并且注意剪枝 如果调料还没选完都已经大于n了 那么就不用再往下了

[p2089] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include<iostream>  
using namespace std;
const int N=5020;
int n,sum=0;
int mem[59055][20];
int a[N];
int res=0;
void dfs(int x,int sum)
{
if(sum>n) return;
if(x>10)
{
if(sum==n)
{
res++;
for(int i=1;i<n;i++)
{
mem[res][i]=a[i];
}

}
return;
}
for(int i=1;i<=3;i++)
{
a[x]=i;
dfs(x+1,sum+i);
a[x]=0;
}

}

int main()
{
cin>>n;
dfs(1,sum);
cout<<res<<endl;
for(int i=1;i<=res;i++)
{
for(int j=1;j<=10;j++)
{
cout<<mem[i][j]<<" ";
}
cout<<endl;
}
return 0;
}




火柴这道题非常有意思
有两个必须满足的条件
一个是a+b=c
一个是num[a]+num[b]=num[c]-4
最关键的就是对于总和的处理 需要额外写个函数计算二位数及以上的火柴数
也可以用递推求出10-1000的 节省时间到原来的三分之一
也要记得剪枝 如果还没枚举完 火柴数都超了 那么直接return

[p1149] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<bits/stdc++.h>
using namespace std;
int n,m,res=0;
int num[10010]={6,2,5,5,4,5,6,3,7,6};
int arr[10010];

int col(int x)
{
int sum2=0;
if(num[x]>0) return num[x];
else
{
while(x)
{
sum2+=num[x%10];
x/=10;
}
}
return sum2;
}

void dfs(int x,int sum)
{
if(sum>n) return;
if(x>3)
{
if(arr[1]+arr[2]==arr[3] && sum==n) res++;
return;
}

for(int i=0;i<=1000;i++)
{
arr[x]=i;
dfs(x+1,sum+col(i));
arr[x]=0;
}

}

int main()
{
cin>>n;
n-=4; //预处理一下 清晰一点
dfs(1,0);
cout<<res<<endl;
return 0;
}


这道题是有坑的 就是至少添加一个调料
我们可以全局定义一个bool 选择先搜不选 因为从不选搜到第一个有选以后 之后都起码选了一个
也可以定义在函数里 先搜全选

[p2036] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<bits/stdc++.h>
using namespace std;
const int N=20;
int n;
int res=1e9;
int s[N],b[N],st[N];
void dfs(int x)
{
if(x>n)
{
bool has_s=false;
int sum1=1;
int sum2=0;
for(int i=1;i<=n;i++)
{
if(st[i]==1)
{
has_s=true;
sum1*=s[i];
sum2+=b[i];

}
}
if(has_s==true) res=min(res,abs(sum1-sum2));
return;
}
st[x]=1;
dfs(x+1);
st[x]=0;

st[x]=2;
dfs(x+1);
st[x]=0;

}

int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s[i];
cin>>b[i];
}
dfs(1);
cout<<res<<endl;
return 0;
}

接下来是迷宫环节
这道题有一个剪枝难点 和之前的电梯一样
namo就是 走过一次的话 就没必要走多次
还有一点就是 这道题不能回溯 因为路径是单一的 回溯了会重复计数

[P1683] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<bits/stdc++.h>
using namespace std;
const int N=30;
int w,h,res=0;
char zi[N][N];
bool st[N][N];
int zoux[]={-1,0,1,0};
int zouy[]={0,1,0,-1};
void dfs(int x,int y)
{
for(int i=0;i<4;i++)
{
int a=x+zoux[i];
int b=y+zouy[i];
if(a<1 ||a>h ||b<1 ||b>w) continue;
if(zi[a][b]!='.') continue;
if(st[a][b]) continue;
st[a][b]=true;
res++;
dfs(a,b);
}
}
int main()
{
cin>>w>>h;
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++) cin>>zi[i][j];
}
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
{
if(zi[i][j]=='@')
{
st[i][j]=true;
dfs(i,j);
}
}
}
cout<<++res<<endl;
return 0;
}