9.13搜索2

预期一测\Delta
a10010-90
b1001000
c1001000
d1001000
e1001000
f10073-27
g1001000
h1001000
i1001000
总分900783-113

问题 A: 营救(save)

BFS板题,由于BFS的性质,第一次搜到某个点就是最短。

#include<bits/stdc++.h>
using namespace std;
#define tx x+dx[i]
#define ty y+dy[i]
int dx[]={1,0,-1,0},
	dy[]={0,-1,0,1};
int n,a,b,c,d;
int cell[1005][1005];
queue<pair<pair<int,int>,int> > q;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			scanf("%1d",&cell[i][j]),cell[i][j]^=1;
	scanf("%d%d%d%d",&a,&b,&c,&d);
	q.push(make_pair(make_pair(a,b),0));
	cell[a][b]=0;
	while(q.size()){
		int x=q.front().first.first,y=q.front().first.second,z=q.front().second;
		q.pop();
		for(int i=0;i<4;++i)
			if(cell[tx][ty]){
				cell[tx][ty]=0;
				if(tx==c && ty==d) return cout<<z+1,0;
				q.push(make_pair(make_pair(tx,ty),z+1));
			}
	}
	return 0;
}

问题 B: 细胞(cell)

BFS板题,对于每一个不为 0 的点从该点BFS,将所有可到达的点都变为 0 即为同一个细胞,将答案加一。

#include<bits/stdc++.h>
using namespace std;
#define tx x+dx[i]
#define ty y+dy[i]
int dx[]={1,0,-1,0},
	dy[]={0,-1,0,1};
int n,m,ans;
int cell[5001][5001];
queue<pair<int,int> > q;
void bfs(int a,int b){
	q.push(make_pair(a,b));
	cell[a][b]=0;
	while(q.size()){
		int x=q.front().first,y=q.front().second;
		q.pop();
		for(int i=0;i<4;++i)
			if(cell[tx][ty])
				cell[tx][ty]=0,q.push(make_pair(tx,ty));
	}
}
char c;
signed main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			scanf("%1d",&cell[i][j]);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			if(cell[i][j])	bfs(i,j),ans++;
	return cout<<ans,0;
}

问题 C: 体积(volume)

DFS板题,对于每一个只有选或不选,2^{20}可过。

#include<bits/stdc++.h>
using namespace std;
bool v[100000];
int a[22],n,ans;
inline void dfs(int s,int x){
	if(x>n){
		if(!v[s]) v[s]=1,ans++;
		return ;
	}
	dfs(s+a[x],x+1);
	dfs(s,x+1);
}
signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",a+i);
	dfs(0,1);
	return cout<<ans-1,0;
}

问题 D: 数的拆分(decompose)

DFS(int hp,int last),hp 表示当前还剩多少没拆分, last 表示当前可选最小。

#include<bits/stdc++.h>
using namespace std;
int p[22],l,n,tot;
void pr(){
	tot++;
	cout<<p[1];
	for(int i=2;i<=l;i++)
		printf("+%d",p[i]);
	puts("");
}
void dfs(int hp,int la){
	if(hp==0) return pr();
	for(int i=la;i<=hp;i++){
		p[++l]=i;
		dfs(hp-i,i);
		p[l--]=0;
	}
}
signed main(){
	scanf("%d",&n);
	dfs(n,1);
	printf("total=%d",tot);
}

问题 E: 全排列问题(form)

DFS 板题

#include<bits/stdc++.h>
using namespace std;
int p[10],n,tot;
bool v[10];
void pr(){
	for(int i=1;i<=n;i++)
		printf("%5d",p[i]);
	puts("");
}
void dfs(int l){
	if(l==n) return pr();
	for(int i=1;i<=n;i++){
		if(!v[i]){
			p[l+1]=i;
			v[i]=1;
			dfs(l+1);
			v[i]=0;
		}
	}
}
signed main(){
	scanf("%d",&n);
	dfs(0);
	return 0;
}

问题 F: 最佳调度问题

枚举当前工作分给哪台机器,加两个小优化,一个是当前最大值若大于已有答案,就返回,一个是从大到小枚举。

#include<bits/stdc++.h>
using namespace std;
int n,k,t[101],f[1001],ans=INT_MAX;
void find(int x,int y) {
	if(y>=ans) return ;
	if(x>n){
		ans=min(y,ans);
		return ;
	}
	for(int i=1;i<=k;++i) {
		f[i]+=t[x];
		find(x+1,max(y,f[i]));
		f[i]-=t[x];
	}
}
int main() {
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;++i) scanf("%d",t+i);
	sort(t+1,t+n+1);
	reverse(t+1,t+n+1);
	find(1,0);
	return printf("%d",ans),0;
}

问题 G: 埃及分数

迭代加深,限定分出的个数,从小到大枚举分数

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e3+5,INF=1e9;
int a,b,len;
LL xt,yt,s,st[maxn],ans[maxn];
LL gcd(LL x,LL y) {return y==0 ? x:gcd(y,x%y);}
bool dfs(LL lst,int tot,LL x,LL y) {
	if (tot==len) {
		if(ans[len]>st[len]) for(int i=1;i<=len;++i) ans[i]=st[i];
		return true;
	}
	bool pd=false;
	for (LL i=max(lst+1,(y+x-1)/x);;++i) {
		yt=i/gcd(i,y)*y;
		xt=x*(yt/y)-yt/i;
		s=gcd(xt,yt);
		xt/=s,yt/=s;
		if(1.0*xt/yt*i>len-1-tot) return pd;
		st[tot+1]=i;
		if(dfs(i,tot+1,xt,yt)) pd=true;
	}
}
int main() {
	scanf("%d%d",&a,&b);
	for(len=1;;++len) {
		ans[len]=INF;
		if (dfs(0,0,a,b)) {
			for (int i=1;i<len;++i) printf("%lld ",ans[i]);
			return printf("%lld\n",ans[len]),0;
		}
	}
	return 0;
}

问题 H: 金币问题II

试验可知,1e12最多不超过1000000,可对1000000以内预处理出等差数列前缀和,以及平方和,

对每一 n 二分查找第一个大于 n 的等差数列前缀和,即可得出答案。

整体复杂度为O\left ( 1000000 +1000*log1000000\right ),此题可过。

#include<bits/stdc++.h>
using namespace std;
#define N 4500000
long long dc[N+2],pf[N+2];
signed main(){
	srand(time(0));
	for(long long i=1;i<=N;i++){
		dc[i]=dc[i-1]+i;
		pf[i]=pf[i-1]+i*i;
	}
	long long n;
	while(cin>>n && n){
		int p=upper_bound(dc+1,dc+N+1,n)-dc;
		long long ans=pf[p-1]+(n-dc[p-1])*(long long)p;
		printf("%lld\n",ans);
	}
}

问题 I: 生日蛋糕

一道较难的搜索剪枝。

(1)当前已有体积比 n 大,减掉。

(2)当前已有表面积比已有答案大,减掉。

(3)当前已有体积加上后面可能获得的最大体积比n小,减掉。

关于最开始底层的枚举。

(1)假设体积都堆到最底层,可得高度下限 m,半径上限\sqrt{n/m}

(2)假设表面积都堆到最底层,可得半径下限 m,高度上限n/(m*m)。

#include<bits/stdc++.h>
using namespace std;
int n,m,ans=0x3f3f3f3f;
inline void dfs(int x,int r,int h,int s,int v){
	if(s>ans || v>n) return;//剪枝1,2
	if(x==m && v==n){
		ans=min(ans,s);
		return;
	} 
	else if(v+(h*r*r)*(m-x)<=n) return;//剪枝3
	for(int h1=h-1;h1>=m-x;h1--)
		for(int r1=r-1;r1>=m-x;r1--)
			dfs(x+1,r1,h1,s+2*r1*h1,v+r1*r1*h1);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int h=n/(m*m);h>=m;h--)
		for(int r=n/m/2;r>=m;r--)
			dfs(1,r,h,r*r+2*r*h,h*r*r);
	printf("%d",ans);
	return 0;
}

总结

大部分为搜索基础题,后几道需要好好思考。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值