暴力枚举优化
P2089 烤鸡
直接十个for暴力也可以
用递归简化一些
- 有了十种配料并且总配料数正确,则存入一组数据
- 总配料超出就不管,看下一个
- 循环1~3,配料轮流加
- 最后输出存入的所有数据
递归: 结束条件:总调料数达到10,总调味度到达n,就把m2存到m1,
设两个数组一个m1二维数组,存储所有配料可能
一个m2一维数组,存储当前递归符合题意的一种配料组合
最后把总数和m1数组全部输出
#include <bits/stdc++.h>
using namespace std;
int n,kind,m1[10000][10],m2[10];
void peiliao(int total,int a)
{
if(a==10)
{
if(total==n)
{
for(int i=0;i<10;i++) m1[kind][i]=m2[i];
kind++;
}
}
else if(total>n) ;
else
for(int i=1;i<=3;i++)
{
m2[a]=i;
peiliao(total+i,a+1);
}
}
int main()
{
cin>>n;
peiliao(0,0);
cout<<kind<<endl;
for(int i=0;i<kind;i++)
{
for(int j=0;j<10;j++) cout<<m1[i][j]<<" ";
cout<<endl;
}
return 0;
}
P1036 选数
优化了一下不降原则
for(int i=y;i<=n;i++)
从y开始,以确保不会选到前面已经满足的一组数据
#include <bits/stdc++.h>
using namespace std;
int n,k,a[21],s=0,ans=0;
bool st[21];
bool isPrime(int x) {
if (x<2)
return false;
for (int i = 2; i <= sqrt(x); i += 1) {
if (x % i == 0)
return false;
}
return true;
}
void dfs(int x,int y)
{
if(x==k)
{
if(isPrime(s)) ans++;
return;
}
for(int i=y;i<=n;i++) //注意
{
st[i]=false;
s+=a[i];
dfs(x+1,i+1);
s-=a[i];
st[i]=true;
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
st[i]=true;
}
dfs(0,1);
cout<<ans;
return 0;
}
P1618 三连击(升级版)
思想:
- 数组
num
统计1~9出现次数 - 直接用倍数乘每一次i得到三个三位数
- 把三个三位数拆分得到1~9出现次数
flag
- 注意每次遍历更新
num
,flag
#include <bits/stdc++.h>
using namespace std;
int num[10],ans;
bool flag=true;
int main()
{
int a,b,c,A,B,C;
cin>>a>>b>>c;
for(int i=1;i*c<=1000;i++)//注意写成i<1000/c会不过
//循环不从三位数开始,可能倍速abc就是192 384 576这样的极端
{
A=i*a,B=i*b,C=i*c;
//题目保证A<B<C,因此i*c最大,能进来就已经满足三位数前提了
//统计1~9出现次数
for(int j=1;j<=3;j++)
{
num[A%10]++;
A/=10;
}
for(int j=1;j<=3;j++)
{
num[B%10]++;
B/=10;
}
for(int j=1;j<=3;j++)
{
num[C%10]++;
C/=10;
}
for(int j=1;j<=9;j++)
{
if(num[j]!=1)
{
flag=false;//不满足题意
break;
}
}
if(flag==true)
{
cout<<i*a<<" "<<i*b<<" "<<i*c<<endl;
ans++;
}
else flag=true; //记得更新
memset(num,0,sizeof num);
}
if(!ans) cout<<"No!!!";
return 0;
}
P1157 组合的输出
套板子,注意后面的数一定要比前面的数大
#include <bits/stdc++.h>
using namespace std;
int a[50];
bool st[10];
int n,r;
void print()
{
for(int i=0;i<r;i++)
cout<<setw(3)<<a[i];
cout<<endl;
}
void dfs(int u)
{
if(u==r) //注意是和r比较不是和n
{
print();
return;
}
for(int i=1;i<=n;i++)
{
if(!st[i]&&i>a[u-1]||u==0)
{
a[u]=i;
st[i]=true;
dfs(u+1);
a[u]=0;
st[i]=false;
}
}
}
int main()
{
cin>>n>>r;
dfs(0);
return 0;
}
P3392 涂条纹
直接暴力一部分测试点会超时
每一次枚举:
1~i是白色,i+1到 j 行是蓝色, j+1到n行是红色,然后每一种涂法更新最小值
for(int i=1;i<=n-2;i++)
for(int j=i+1;j<=n-1;j++)
{
ans=0;
for(int k=1;k<=i;k++)
for(int g=1;g<=m;g++) if(c[k][g]!='W') ans++;
for(int k=i+1;k<=j;k++)
for(int g=1;g<=m;g++) if(c[k][g]!='B') ans++;
for(int k=j+1;k<=n;k++)
for(int g=1;g<=m;g++) if(c[k][g]!='R') ans++;
mi=min(ans,mi);
}
优化做法:
开数组w[i],b[i],r[i]
,分别表示把前i行涂成白、蓝、红需要涂的格子数
设第1行到第i行是白色
第i+1行到第 j 行是蓝色
则第 j+1行到第 n 行是红色
在 **w[i]+b[j]-b[i]+r[n]-r[j]
**中
b[j]-b[i]
计算第 i+1
行到第 j
行之间的不匹配 'B'
的个数。
r[n]-r[j]
,计算从第 j+1
行到最后一行的不匹配 'R'
的总数。
#include <bits/stdc++.h>
using namespace std;
int n,m,ans=0x3f3f3f3f,w[51],b[51],r[51];
string s;
int check(char c)
{
int cnt=0;
for(int i=0;i<m;i++)
if(s[i]!=c) cnt++;
return cnt;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s;
w[i]=w[i-1]+check('W');
b[i]=b[i-1]+check('B');
r[i]=r[i-1]+check('R');
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<n;j++) //注意j<n,别等于,r没位置放了
ans=min(ans,w[i]+b[j]-b[i]+r[n]-r[j]);
cout<<ans;
return 0;
}
P3654 First Step
思想:
- 只需要判断向右或者向下是否有空位
- 注意当
k=1
时横着站和竖着站都一样,会重复计算,要除以2
递归: 结束条件: 连续可站位数==人数,站法加一
不满足空位和边界范围就返回
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
typedef pair<int,int> PII;
int n,m,k,dx[2]={1,0},dy[2]={0,1};
char g[N][N];
int ans;
void dfs(int x,int y,int i,int j)
{
if(j>k)
{
ans++;
return;
}
if(g[x][y]!='.'||x<0||y<0||x>=n||y>=m) return;
dfs(x+dx[i],y+dy[i],i,j+1);
return;
}
int main()
{
cin>>n>>m>>k;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>g[i][j];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(g[i][j]=='.')
for(int c=0;c<2;c++)
dfs(i,j,c,1);
if(k==1) ans/=2;
cout<<ans;
return 0;
}
P2036 PERKET
递归:
结束条件:调用的数量等于总数,不存在清水情况,特判返回重新找
分为添加和不添加两种情况
#include <bits/stdc++.h>
using namespace std;
const int N = 15;
int n,m,ans=0x3f3f3f3f,a[N],b[N];
void dfs(int i,int suan,int ku)
{
if(i==n)
{
if(suan==1&&ku==0) return; //判断清水的情况
ans=min(ans,abs(suan-ku));
return;
}
dfs(i+1,suan*a[i],ku+b[i]); //添加
dfs(i+1,suan,ku); //不添加
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i]>>b[i];
dfs(0,1,0);
cout<<ans;
return 0;
}