DFS对于算法竞赛骗分和打表的重要性

这篇博客是在看到一篇评论发的

第一个评论

1.骗分的适用范围

众所周知,骗分或打表这在比赛中还是很有用的;

但如果你不知道如何正确地去骗分或打表,会导致你错失很多分数

适用范围:

1.在你遇到一点都不会的题时题面看着也能搜索时,你就可以试试DFS骗分了

2.或者是遇到不会的题时数据也很小,比如n<=30或n<=50等,你就可以考虑用打表做了

3.小技巧:在遇到[USACO]这个东西时,你直接输出样例就有分

2.题目示范

1.暴力搜索骗分

题目

这道题十分的像搜索,所以天真的我便拿搜索写了这道题;

代码:

#include<bits/stdc++.h>
using namespace std;
struct ys{
	int q,w,t,s;
};
int n,m,dt[1007][1007],x,y,z,dx,dy,mv[5][2]={{0,0},{1,0},{0,1},{-1,0},{0,-1}},ans;
bool vis[1007][1007];
ys k;
queue<ys>q;
int main() {
	memset(dt,-1,sizeof dt);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>z>>x>>y;
		dt[x][y]=z;
	}
	q.push(ys{1,1,0,0});
	if(dt[1][1]==0){
		ans++;
	}
	vis[1][1]=true;
	while(!q.empty()){
		k=q.front();
		ans=max(k.s,ans);
		q.pop();
		for(int i=1;i<=4;i++){
			dx=k.q+mv[i][0];
			dy=k.w+mv[i][1];
			if(dx<1||dy<1||dx>n||dy>n||vis[dx][dy]){
				continue;
			}
			vis[dx][dy]=true;
			if(dt[dx][dy]>=k.t){
				q.push(ys{dx,dy,dt[dx][dy],k.s+1});
			}
			q.push(ys{dx,dy,k.t+1,k.s});
		}
	}
	cout<<ans;
	return 0;
}

但我又看见了这个:而机器人每一时刻只能够移动一格或停留在原地不动

然后结果也是惨不忍睹:

而这道题的正解为dp;

这也启示了我们,你不会dp也能拿分,而在考场上这10分可能是至关重要的;

正解:你需要用当前这个序号的鼹鼠为结尾求可以打死鼹鼠的最大数;

代码:

#include<bits/stdc++.h>
using namespace std;
struct ys{
	int x,y,t;
};
int n,m,f[10007],ans;
ys a[10007];
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>a[i].t>>a[i].x>>a[i].y;//一定先是t
	}
	for(int i=1;i<=m;i++){
		f[i]=1;
		for(int j=i-1;j>=1;j--){
			if(abs(a[i].x-a[j].x)+abs(a[i].y-a[j].y)<=a[i].t-a[j].t){//看时间够不够
				f[i]=max(f[i],f[j]+1);//求最大值
			}
		}
		ans=max(f[i],ans);//求最大值
	}
	cout<<ans;
	return 0 ;	
}

可见,虽然dp难但骗一点分还是很容易的;

2.打表得分

题目

题目十分的通俗易懂,直接使用DFS大法!!!

于是5min写的代码便新鲜出炉了:

#include<bits/stdc++.h>
using namespace std;
long long n,ans,num;
bool vis[45];
void dfs(int x,int y){//x是当前拿的数的总和,y是上一个拿的数
	if(x==num){
		ans++;
		return;
	}
	for(int i=y+1;i<=n;i++){//不能取比前一个大的
		if(x+i>num){
			
			continue;
		}
		dfs(x+i,i);
	}
	return;
}
int main() {
	cin>>n;
	num=(n*n+n)/4;//把总和分成两部分
	dfs(0,0);
	cout<<ans/2;//去重
	return 0;
}

虽然答案正确,但时间复杂度:

30
4339640
--------------------------------
Process exited after 2.987 seconds with return value 0
请按任意键继续. . .

通过不了;

于是我绞尽脑汁想到了打表,就是把每个答案都搜出来并存起来

虽然说:

39
1512776590
--------------------------------
Process exited after 1800 seconds with return value 0
请按任意键继续. . .

但O(1)的时间复杂度保证了我不会超时;

代码:

#include<bits/stdc++.h>
using namespace std;
long long n,a[45]={0,0,1,1,1,1,2,4,7,11,20,35,62,110,198,361,657,1205,2220,4110,7636,14230,26610,49910,93846,176871,334136,632602,1199892,2279914,4339640,8273610,15796439,30200344,57816630,110826888,212681976,408587849,785794088,1512776590};
int main() {
    cin>>n;
    if((n*n+n)%4!=0){
        cout<<0;
    }else{
        cout<<a[n];
    }
    return 0;
}

3.总结

我通过一系列骗分总结出了经验:

只要学好DFS不管什么题都能拿亿点分(骗分很重要)

^_^

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值