算法竞赛进阶指南学习day13

CH2401

题目:作为惩罚,GY被遣送去帮助某神牛给女生送礼物(GY:貌似是个好差事)但是在GY看到礼物之后,他就不这么认为了。某神牛有N个礼物,且异常沉重,但是GY的力气也异常的大(-_-b),他一次可以搬动重量和在w(w<=2^31-1)以下的任意多个物品。GY希望一次搬掉尽量重的一些物品,请你告诉他在他的力气范围内一次性能搬动的最大重量是多少。

本题直接dfs也可以写,但是看到数据规模(对于100%的数据 N<=45 W<=2^31-1),直接dfs肯定要超时的;所以用到双向搜索

 如图就是dfs(左),和双向搜索(右)的区别(好丑)

 

 那么可以将数据分成两半,前一半朴素dfs,存储运行结果,后一半匹配前一半结果进行搜索

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
long long w,n;
long long now=0;
long long a[100],b[1<<23+1];
long long m;
long long ans=0; 
bool cmp(int a,int b){
	return a>b;
} 

void dfs1(int s,int e){
	if(now>w){//加多了 
		return ;
	}
	if(s>e){//若遍历完 
		m++;
		b[m]=now;
	//	cout<<now<<" ";
		return ;
	}
	dfs1(s+1,e);//不拿这个 
	now+=a[s];
	dfs1(s+1,e);//拿 
	now-=a[s]; 
}
void dfs2(int s,int e){
	if(now>w){//加多了 
		return ;
	}
	if(s>e){//若遍历完 
		if(b[1]+now > w) return ;//如果现在的值加上前半最小的都比w大就没有再二分的必要 
		long long c=w-now;
		ans=max((b[upper_bound(b+1,b+1+m,c)-b-1]+now),ans);
		return ;
	}
	dfs2(s+1,e);//不拿这个 
	now+=a[s];
	dfs2(s+1,e);//拿 
	now-=a[s]; 
}
int main(){
	cin>>w>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+1+n,cmp);
	dfs1(1,n/2);
	/*
	 b数组存储了所有前一半可以加出来的可行情况 
	for(int i=1;i<=m;i++){
		cout<<b[i]<<" ";
	} */
	sort(b+1,b+m+1);
	dfs2(n/2+1,n);
	cout<<ans;
	return 0;
}
/*
20 5
7
5
4
18
1
*/

CH2501

思路:以每个1为起点,分别进行深搜

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
int n,m;
char a[3000][3000]; 
int s[3000][3000],l[3000][3000];
int m1[4]={-1,1,0,0};
int m2[5]={0,0-1,1};
queue<pair<int,int> > q; 
int main(){
	memset(l,-1,sizeof(l));
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%s",a[i]+1);
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]='1'){
				l[i][j]=0;
				q.push(make_pair(i,j));
			}
		}
	}
	while(q.size()){
		pair<int,int> now=q.front();
		q.pop();
		for(int i=0;i<4;i++){
			pair<int,int> next=make_pair((now.first+m1[i]),(now.second +m2[i]));
			if(next.first <1||next.second <1||next.first >n||next.second >m) {
				continue;
			}
			if(l[next.first][next.second]==-1){
				l[next.first][next.second]=l[now.first ][now.second ]+1;	
				q.push(next); 
			}
		} 
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout<<l[i]<<" ";
		}
		cout<<endl;
	}
	

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值