9.13集训小结

T1:

第一题icon-default.png?t=L892http://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:

第二题icon-default.png?t=L892http://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:

第三题icon-default.png?t=L892http://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:

第四题icon-default.png?t=L892http://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:

第五题icon-default.png?t=L892http://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:

第六题icon-default.png?t=L892http://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:

第七题icon-default.png?t=L892http://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/UVA12558icon-default.png?t=L892https://www.luogu.com.cn/problem/solution/UVA12558        看得懂看,看不懂算

T8:

第八题icon-default.png?t=L892http://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这么大,事实上我们可以用平方数前缀和的公式:\large \frac{n*(n+1)*(2n+1)}{6}遍历找到距离所求天数最近的平方前缀和,这时可以知道还有多少天剩余并且知道当天给的金币,就可以算出答案。

但这样是过不了的,我们可以将遍历查找优化成二分查找,时间复杂度进一步降低,这道题就可以稳稳的过了

#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:

第九题icon-default.png?t=L892http://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(侵删

总结:

             今天做的就比第一次考搜索专题的时候就要好的多了。对搜索的理解、掌握也更加深入和熟练,希望能抓住这样的感觉,继续努力加油,以进一步提高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值