T1:
第一题http://118.31.67.228/problem.php?cid=1018&pid=0
样例输入:
3 001 101 100 1 1 3 3
样例输出:
4
题解:
老DFS一分没有了直接用BFS跑一遍注意还是要取最小的那一个点,ans还是要加一个取min
(按理说不用)
注意!!!网上提交请记得关freopen
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
using namespace std;
int n;
int x1,y1,x2,y2;
char ma[1010][1010];
int mov[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int dis[1010][1010];
int ans;
queue< pair<int , int> >q;
inline bool pd(int x,int y,int i)
{
if(x+mov[i][0]>=0 && x+mov[i][0]<n && y+mov[i][1]>=0 && y+mov[i][1]<n)return 1;
else return 0;
}
inline void BFS()
{
memset(dis,-1,sizeof(dis));
q.push(make_pair(x1,y1));
dis[x1][y1]=0;
while(!q.empty()){
int nowx=q.front().first,nowy=q.front().second;
q.pop();
if(nowx==x2 && nowy==y2){
ans=min(ans,dis[x2][y2]);
//return;
}
for(int i=0;i<4;i++){
if( pd(nowx,nowy,i)==1 && dis[nowx+mov[i][0]][nowy+mov[i][1]]==-1 &&
ma[nowx+mov[i][0]][nowy+mov[i][1]]=='0'){
dis[nowx+mov[i][0]][nowy+mov[i][1]]=dis[nowx][nowy]+1;
q.push(make_pair(nowx+mov[i][0],nowy+mov[i][1]));
}
}
}
}
int main(void)
{
//freopen("1.in","r",stdin);
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s",ma[i]);
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1--;y1--;x2--;y2--;
ans=1000000;
BFS();
printf("%d",ans);
}
T2:
第二题http://118.31.67.228/problem.php?cid=1018&pid=1
样例输入:
4 10 0234500067 1034560500 2045600671 0000000089
样例输出:
4
题解:
同样老DFS一分没有了,对于每个不是0的位置进行染色,最后染色个数就是答案(真不知道还需要写些啥了)
#include<cstdio>
#include<queue>
#include<cstring>
#include<string>
using namespace std;
int n,m;
char ma[3010][3010];
int col[3010][3010];
int mov[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int ans;
queue< pair<int , int> >q;
inline bool pd(int x,int y,int i)
{
if(x+mov[i][0]>=0 && x+mov[i][0]<n && y+mov[i][1]>=0 && y+mov[i][1]<m)return 1;
else return 0;
}
inline void BFS(int x,int y,int color)
{
q.push(make_pair(x,y));
col[x][y]=color;
while(!q.empty()){
int nowx=q.front().first,nowy=q.front().second;
q.pop();
for(int i=0;i<4;i++){
if( pd(nowx,nowy,i)==1 && col[nowx+mov[i][0]][nowy+mov[i][1]]==0 &&
ma[nowx+mov[i][0]][nowy+mov[i][1]]!='0'){
col[nowx+mov[i][0]][nowy+mov[i][1]]=color;
q.push(make_pair(nowx+mov[i][0],nowy+mov[i][1]));
}
}
}
}
int main(void)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%s",ma[i]);
ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(ma[i][j]!='0' && col[i][j]==0){
ans++;
BFS(i,j,ans);
}
}
}
printf("%d",ans);
}
/*
4 10
0234500067
1034560500
2045600671
0000000089
*/
T3:
第三题http://118.31.67.228/problem.php?cid=1018&pid=2
样例输入:
3
1 3 4
样例输出:
4
题解:
这道题也是度不难大,直接枚举每一种物品选或着不选的情况,再利用桶进行计数,时间复杂为2^n。(题目能做完全是因为数据范围小,当物品价值增大,就要将桶换成set)
#include<cstdio>
using namespace std;
int n;
int val[1000];
int cnt[10000];
int sk[1000];
int sum,ans;
inline void dfs(int depth)
{
if(depth==n){
sum=0;
for(int i=0;i<depth;i++)sum+=sk[i]*val[i];
cnt[sum]++;
return ;
}
for(int i=0;i<2;i++){
sk[depth]=i;
dfs(depth+1);
sk[depth]=0;
}
}
int main(void)
{
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&val[i]);
dfs(0);
ans=0;
for(int i=1;i<=2000;i++)if(cnt[i]>0)ans++;
printf("%d",ans);
}
T4:
第四题http://118.31.67.228/problem.php?cid=1018&pid=3
样例输入:
4
样例输出:
1+1+1+1 1+1+2 1+3 2+2 4 total=5
题解:
这道题好像看着有点难,但是事实上还好,每次搜索的当前数要大于等于前一个搜出来的数,小于等于剩下的值,注意输出格式;在dfs中记录上一层所选的数字、和还剩下的值;其他的就没有太多细节。
#include<cstdio>
using namespace std;
int n,ans;
int sk[1000];
template <typename T>inline void prt(T x)
{
if(x>9)prt(x/10);
putchar(x%10+'0');
}
inline void dfs(int fath,int depth,int state)
{
if(state==n){
for(int i=1;i<depth-1;i++){
prt(sk[i]);
putchar('+');
}
prt(sk[depth-1]);
putchar('\n');
ans++;
return ;
}
for(int i=fath;i<=n-state;i++){
if(state+i<=n){
sk[depth]=i;
dfs(i,depth+1,state+i);
sk[depth]=0;
}
}
}
int main(void)
{
// freopen("2.out","w",stdout);
scanf("%d",&n);
dfs(1,1,0);
printf("total=%d",ans);
}
T5:
第五题http://118.31.67.228/problem.php?cid=1018&pid=4
样例输入:
3
样例输出:
1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1
题解:
见代码,注意一个数占五列。
#include<cstdio>
using namespace std;
int n;
int sk[1000];
bool vis[1000];
template <typename T>inline void prt(T x)
{
if(x>9)prt(x/10);
putchar(x%10+'0');
}
inline void dfs(int depth)
{
if(depth==n+1){
for(int i=1;i<depth;i++){
if(sk[i]<10){
putchar(' ');
putchar(' ');
putchar(' ');
putchar(' ');
}
else{
putchar(' ');
putchar(' ');
putchar(' ');
}
prt(sk[i]);
}
putchar('\n');
return ;
}
for(int i=1;i<=n;i++){
if(vis[i]==0){
vis[i]=1;
sk[depth]=i;
dfs(depth+1);
sk[depth]=0;
vis[i]=0;
}
}
}
int main(void)
{
//freopen("2.out","w",stdout);
scanf("%d",&n);
dfs(1);
}
T6:
第六题http://118.31.67.228/problem.php?cid=1018&pid=5
样例输入:
7 3 2 14 4 16 6 5 3
样例输出:
17
题解:
这道题先写了一个暴力搜索,然后看着会T于是就去写了一个WA贪心。然后发现贪心的正确性无法保证,于是就去想剪枝,然后TLE了(time limit enough)
剪枝1:
将耗时从大到小的排一遍,再进行搜索;
sort(val+1,val+1+n,tmp);
剪枝2:
当当前的state>=已经搜到的答案时直接return(这个等于号直接让程序快了500ms,相当玄学)
if(state>=ans)return;
#include<cstdio>
#include<algorithm>
using namespace std;
int n,k,ans;
int sk[1000];
int val[1000];
int sum;
template <typename T>inline void prt(T x)
{
if(x>9)prt(x/10);
putchar(x%10+'0');
}
inline void dfs(int depth,int state)
{
if(state>=ans)return;
if(depth==n+1){
ans=min(ans,state);
return ;
}
for(int i=1;i<=k;i++){
sk[i]+=val[depth];
dfs(depth+1,max(state,sk[i]));
sk[i]-=val[depth];
}
}
inline bool tmp(int xx,int yy){return xx>yy;}
int main(void)
{
scanf("%d%d",&n,&k);
sum=0;
for(int i=1;i<=n;i++)scanf("%d",&val[i]);
ans=99999999;
sort(val+1,val+1+n,tmp);
dfs(1,0);
printf("%d",ans);
}
T7:
第七题http://118.31.67.228/problem.php?cid=1018&pid=6
样例输入:
19 45
样例输出:
5 6 18
题解:
被这古代埃及数学之美ex了一下午
直接上题解:
迭代加深搜索--埃及分数_unintended-CSDN博客需要用单位分数1/a表示任意分数,并且加数中不能有相同的,加数少的比加数多的好,个数相同时,最小的分数越大越好。首先,加数的个数不确定,bfs的话,从第一个比a/b小的数1/c开始,可能从所有比它小的数开始加,一层都遍历不完。dfs,如果直接从1/c开始,找到答案可能很慢,对于加数个数和大小的限制实现起来很慢。迭代加深搜索:从小到大枚举深度上限maxd,每次执行只考虑深度不超过https://blog.csdn.net/SM_545/article/details/76653548?utm_source=blogxgwz0https://www.luogu.com.cn/problem/solution/UVA12558https://www.luogu.com.cn/problem/solution/UVA12558 看得懂看,看不懂算
T8:
第八题http://118.31.67.228/problem.php?cid=1018&pid=7
样例输入:
10 6 7 11 15 16 100 10000 1000 21 22 0
样例输出:
30 14 18 35 55 61 945 942820 29820 91 98
题解:
这道题关键在于找规律,看上去n很大,有10^12这么大,事实上我们可以用平方数前缀和的公式:遍历找到距离所求天数最近的平方前缀和,这时可以知道还有多少天剩余并且知道当天给的金币,就可以算出答案。
但这样是过不了的,我们可以将遍历查找优化成二分查找,时间复杂度进一步降低,这道题就可以稳稳的过了
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
long long n;
long long sum,pos;
long long ans;
template <typename T>inline void in(T &x)
{
T ch=getchar(),xx=0,fw=1;
while(!isdigit((int)ch)){if(ch=='-')fw=-1;ch=getchar();}
while(isdigit((int)ch)){xx=(xx<<1)+(xx<<3)+ch-'0';ch=getchar();}
x=xx*fw;
}
template <typename T>inline void prt(T x)
{
if(x>9)prt(x/10);
putchar((int)(x%10+'0'));
}
int main(void)
{
while(1){
in(n);
if(n==0)break;
ans=0,sum=0,pos=0;
for(long long i=1;i<=n;i++){
if(sum+i>n)break;
else{
ans+=i*i;
sum+=i;
pos=i;
}
}
ans+=(n-sum)*(pos+1ll);
prt(ans);
putchar('\n');
}
}
(水数据没二分就过了
T9:
第九题http://118.31.67.228/problem.php?cid=1018&pid=8
样例输入:
100 2
样例输出:
68
题解:
啊哈,大家的思路一定和我一样——DFS,找个数组存储半径和高,可是如单单使用DFS不加剪枝的话,10分——20分。
所以,我们来想一想如何剪枝
###1.当前的奶油面积+之后的最小奶油面积>现在已求出的的最小奶油面积——果断return;
###2.当前的体积>n,return;
###3.当前的体积+之后的最大体积<体积总数,果断return;
###4.发现每次枚举半径和高时,是从上一个的半径和高,到还剩下的层数。为什么呢,是因为每一层的半径和高都要比下一层的小1,所以你得每一层都留一个1,so,是从上一个的半径和高,到还剩下的层数;
OK,现在我们加上剪枝之后就可以A了
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
int r[30],h[30],minn=2147483647,n,m;
void dfs(int x,int y,int k,int z)
{ if(y<0) return;
if(x>m+1) return;
if(k>=minn) return;
if(y==0&&x==m+1)
{ k+=r[1]*r[1];
if(k<minn) minn=k;
return;
}
if(k+z+r[1]*r[1]>minn) return;
if(y-(r[x-1])*(r[x-1])*(h[x-1])*z>0) return;
for(int i=r[x-1]-1;i>=z;i--)
for(int j=h[x-1]-1;j>=z;j--)
{
if(y-i*i*j>=0&&x+1<=m+1)
{ r[x]=i;
h[x]=j;
dfs(x+1,y-i*i*j,k+(i*2*j),z-1);
h[x]=0;
r[x]=0;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
r[0]=(int)sqrt(n);
h[0]=(int)sqrt(n);
dfs(1,n,0,m);
if(minn==2147483647) printf("%d",0);
else printf("%d",minn);
return 0;
}
——luoguZcus(侵删
总结:
今天做的就比第一次考搜索专题的时候就要好的多了。对搜索的理解、掌握也更加深入和熟练,希望能抓住这样的感觉,继续努力加油,以进一步提高