大法师(简单题总结)

第一题:吃奶酪

它也有两个小剪枝

1.就是当搜到一个数,但是它已经超过了已知答案,就return。

2.就是提前把距离都预处理出来

Code:

#include<bits/stdc++.h>
using namespace std;
int n;
bool vis[1005];
double ans=10000000,x[1005],y[1005],len[1010][1010];
void dfs(int step,double l,int now){
	if(l>ans) return;//剪枝1
	if(step==n){
		if(ans>l) ans=l;
		return;
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]) continue;
		vis[i]=0;
		dfs(step+1,l+len[now][i],i);
		vis[i]=1;
	}
}
int main(){
	scanf("%d",&n);
	x[0]=0;y[0]=0;
	for(int i=1;i<=n;i++){
		scanf("%lf%lf",&x[i],&y[i]);
		vis[i]=1;
	}
	for(int i=0;i<=n;i++){
		for(int j=0;j<=n;j++){
			len[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));//剪枝2
		} 
	}
	dfs(0,0.0,0);
	printf("%.2lf",ans); 
}

第二题:健康的荷斯坦奶牛

这题有点复杂(至少我这么觉得)

虽然这是pj-,但我觉得这是tg-

我看这道题,想了半天递归的出口到底是什么。

然后我想就稍稍看了一眼题解 ,哦原来这道题要这么想!!好神奇!!

看代码吧,这道题我没想出来。(回头要再看看这道题)

Code:

#include<bits/stdc++.h>
using namespace std;
int G,V,v[3000],g[3000][3000],c[3000],wer[3000],answer=1000000;
bool check(int x){
	for(int i=1;i<=V;i++){
		int ans=0;
		for(int j=1;j<=x;j++)
			ans+=g[c[j]][i]; //非常神奇
		if(ans<v[i]) return false; 
	}
	return true;
}//这个check()函数是我第一次遇见。
void dfs(int t,int s){//t是第几种,s是一共用了几种
	if(t>G){//结束的地方就是当要用的种类已经超过了所有的种类
		if(check(s)){//check()函数,看看这个满足条件吗
			if(s<answer){
				answer=s;
				for(int i=1;i<=answer;i++){
					wer[i]=c[i];
				}
			}
		}
		return; 
	}
    //这个大法师是我觉得最好的地方
	c[s+1]=t;//如果选t
	dfs(t+1,s+1);//大法师
	c[s+1]=0;//回溯
	dfs(t+1,s);//大法师(没选t)
}
int main(){
	scanf("%d",&V);
	for(int i=1;i<=V;i++) scanf("%d",&v[i]);
	scanf("%d",&G);
	for(int i=1;i<=G;i++){
		for(int j=1;j<=V;j++){
			scanf("%d",&g[i][j]); 
	   	}
	}
	dfs(1,0);
	printf("%d",answer);
	for(int i=1;i<=answer;i++) printf(" %d",wer[i]);
	return 0;
} 

第三题:取数游戏

这道题的难点在于可能多个点把一个点设为不可选,所以当回溯时只可以--,

而不能让它直接=0。

#include<bits/stdc++.h>
using namespace std;
int a[100][100],step1,use[100][100],step2,ans,n,m,T;
int a1[8]={1,1,1,0,0,-1,-1,-1},a2[8]={0,1,-1,1,-1,0,1,-1};
void dfs(int step1,int step2,int sum){
	if(step2>m){
		step1++;
		step2=1;
	}
	if(step1>n){
		if(ans<sum) ans=sum; 
		return;
	}
	if(use[step1][step2]==0){
        //就是下面这句有可能有好几个数使得这个地方不可选
		for(int i=0;i<=7;i++) use[step1+a1[i]][step2+a2[i]]++;
		dfs(step1,step2+2,sum+a[step1][step2]);
		for(int i=0;i<=7;i++) use[step1+a1[i]][step2+a2[i]]--;
		//上面这句,只能去-- (要不然就爆炸)
    }
	dfs(step1,step2+1,sum);
}
int main(){
	scanf("%d",&T);
	while(T--){
		ans=0;
		memset(use,0,sizeof(use));
		memset(a,0,sizeof(a));
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				scanf("%d",&a[i][j]);
			}
		}
		dfs(1,1,0);
		printf("%d\n",ans);
	}
	return 0;
} 

第四题:油滴扩展

这道题的半径是难点,关键在于如何确定出来半径的大小

#include<bits/stdc++.h>
using namespace std;
int n;
double area,ans,d1,d2,d3,d4,xx1,yy1,xx2,yy2;
double c[1000],x[1000],y[1000],use[1000],len[105][105];
void dfs(int shot,double sum){
	if(shot>n){
		if(sum>ans) ans=sum;
		return;
	}
	for(int k=1;k<=n;k++){
		if(use[k]==0){
			c[k]=min(
                min(abs(x[k]-d1),abs(x[k]-d2))
                ,
                min(abs(y[k]-d3),abs(y[k]-d4))
            );
			for(int j=1;j<=n;j++)
				if(use[j]) c[k]=min(c[k],len[k][j]-c[j]);
			if(c[k]<0) c[k]=0;
			use[k]=1;
			dfs(shot+1,sum+(M_PI*c[k]*c[k]));
			use[k]=0;
		}
	}
}
int main(){
	scanf("%d%lf%lf%lf%lf",&n,&xx1,&yy1,&xx2,&yy2);
	for(int i=1;i<=n;i++){
		scanf("%lf%lf",&x[i],&y[i]);
		x[i]+=1000;
		y[i]+=1000;
	}
	xx1+=1000,xx2+=1000,yy1+=1000,yy2+=1000;
	d1=min(xx1,xx2);
	d2=max(xx1,xx2);
	d3=min(yy1,yy2);
	d4=max(yy1,yy2);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			len[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
	area=(abs(xx1-xx2)*abs(yy1-yy2));	
	dfs(1,0.0);
	printf("%d",int(area-ans+0.5));
	return 0;
} 

第五题:小埋与扫雷

这道题给的链接,一共有两个!!!

都十分的重要,而我却一个都没看,所以​💩

尤其是八连通,我以为是大于等于8的连通块,实际是8个方向​💩

好吧,但是八连通怎么求还是值得看一眼的,看代码(不要以为我大法师,百凤山不分),我只是懒的写了。

#include<bits/stdc++.h>
using namespace std;
int ans,n,m,a[1005][1005],a1[8]={1,1,1,0,0,-1,-1,-1},a2[8]={1,0,-1,1,-1,1,0,-1};
void bfs(int p,int q){
	if(p>=0&&p<=n&&q>=0&&q<=m&&a[p][q]==-1){
		a[p][q]=2;
		for(int i=0;i<=7;i++) bfs(p+a1[i],q+a2[i]);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n+1;i++)
		for(int j=0;j<=m+1;j++)
			a[i][j]=2;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]==1) continue;
			int jb=0;
			for(int k=0;k<=7;k++) if(a[i+a1[k]][j+a2[k]]==1) jb=1;
			if(jb==1) a[i][j]=2;
			if(jb==0) a[i][j]=-1;
		} 
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]==1||a[i][j]==-1) continue;
			int jb=0;
			for(int k=0;k<=7;k++)	if(a[i+a1[k]][j+a2[k]]==0||a[i+a1[k]][j+a2[k]]==-1) jb=1;
			if(jb==0) ans++,a[i][j]=3;
		} 
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(a[i][j]==-1)	ans++,bfs(i,j);
	cout<<ans;
	return 0;
}

第六题:海战

最开始看这道题的时候我还想,这不就是上面的题的求连通块放下来吗?

于是,真香

它需要判断连通块是否是一个矩形,其实这也十分简单,因为根据第一篇题解

不是矩形一定会这样的景象:

额,我废了好大的劲,可是为啥还是这么丑!!!

所以得出:如果4个格里有仨是有数的则不是矩形!

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1005][1005],ans,rr,yy,ss;
char ch;
void dfs(int p,int q){
	if(p>=0&&q>=0&&p<=n&&q<=m&&a[p][q]==1){
		a[p][q]=2;
		dfs(p+1,q);
		dfs(p-1,q);
		dfs(p,q+1);
		dfs(p,q-1);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>ch;//这里有个天大的疑问,为啥我打scanf就会崩?!
			if(ch=='.') a[i][j]=0;
			else a[i][j]=1;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]==1){
				ans++;
				dfs(i,j);
			}
		}
	}
    //从这开始判断是不是矩形
	for(int i=1;i<=n-1;i++){
		for(int j=1;j<=m-1;j++){
			int sum=a[i][j]+a[i+1][j]+a[i+1][j+1]+a[i][j+1];
			if(sum==6){
				cout<<"Bad placement.";
				return 0;
			}
		}
	}
    // 到这结束
	printf("There are %d ships.",ans);
	return 0;
}

第七题:‘SEARCH'

额, 我不会搜索做,准确来说是不会剪枝,于是我一生气,就用模拟把它做出来了,可是我还是不会用搜索做,所以再等等,我问问大佬,应该就能出来。

模拟code 60ms,吸氧之后45ms:

#include<bits/stdc++.h>
using namespace std;
int n,m,r,a[55][55],cnt=1,way[1005],x,y;
char ch,c[5],ac[55][55];;
void wes(int p,int q,int temp){
    for(int i=q-1;i>=1;i--){
        if(a[p][i]==-1) break;
        a[p][i]=temp;
    }
}
void eas(int p,int q,int temp){
    for(int i=q+1;i<=m;i++){
        if(a[p][i]==-1) break;
        a[p][i]=temp;
    }
}
void sou(int p,int q,int temp){
    for(int i=p+1;i<=n;i++){
        if(a[i][q]==-1) break;
        a[i][q]=temp;
    }
}
void nor(int p,int q,int temp){
    for(int i=p-1;i>=1;i--){
        if(a[i][q]==-1) break;
        a[i][q]=temp;
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>ch;
            if(ch=='*') x=i,y=j,a[i][j]=1;
            if(ch=='X') a[i][j]=-1;
        }
    }
    scanf("%d",&r);
    for(int i=1;i<=r;i++){
        cin>>c;
        if(c[0]=='N') way[++cnt]=4;
        if(c[0]=='S') way[++cnt]=1;
        if(c[0]=='E') way[++cnt]=2;
        if(c[0]=='W') way[++cnt]=3;
    }
    for(int k=2;k<=r+1;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]==k-1){
                    if(way[k]==1) sou(i,j,k);
                    if(way[k]==2) eas(i,j,k);
                    if(way[k]==3) wes(i,j,k);
                    if(way[k]==4) nor(i,j,k);
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]==-1) ac[i][j]='X';
            if(a[i][j]<=r+1&&a[i][j]!=-1) ac[i][j]='.';
            if(a[i][j]==r+1) ac[i][j]='*';
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cout<<ac[i][j];
        }
        cout<<endl;
    }
    return 0;
} 

TLE七个点(不会剪枝😭)code(吸不吸氧一样):

#include<bits/stdc++.h>
using namespace std;
int n,m,r,a[55][55],cnt,way[1005],x,y;
char ch,c[5],ac[55][55];
void dfs(int p,int q,int temp){
    if(way[temp]==0){
        return;
    }
    if(way[temp]==3){
        for(int i=q-1;i>=1;i--){
            if(a[p][i]==-1) break;
            if(a[p][i]<temp) a[p][i]=temp;
            dfs(p,i,temp+1);
        }
    }
    if(way[temp]==2){
        for(int i=q+1;i<=m;i++){
            if(a[p][i]==-1) break;
            if(a[p][i]<temp) a[p][i]=temp;
            dfs(p,i,temp+1);
        }
    }
    if(way[temp]==1){
        for(int i=p+1;i<=n;i++){
            if(a[i][q]==-1) break;
            if(a[i][q]<temp) a[i][q]=temp;
            dfs(i,q,temp+1);
        }
    }
    if(way[temp]==4){
        for(int i=p-1;i>=1;i--){
            if(a[i][q]==-1) break;
            if(a[i][q]<temp) a[i][q]=temp;
            dfs(i,q,temp+1);
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>ch;
            if(ch=='*') x=i,y=j;
            if(ch=='X') a[i][j]=-1;
        }
    }
    scanf("%d",&r);
    for(int i=1;i<=r;i++){
        cin>>c;
        if(c[0]=='N') way[++cnt]=4;
        if(c[0]=='S') way[++cnt]=1;
        if(c[0]=='E') way[++cnt]=2;
        if(c[0]=='W') way[++cnt]=3;
    }
    dfs(x,y,1);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(a[i][j]==-1) ac[i][j]='X';
            if(a[i][j]<=r&&a[i][j]!=-1) ac[i][j]='.';
            if(a[i][j]==r) ac[i][j]='*';
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cout<<ac[i][j];
        }
        cout<<endl;
    }
    return 0;
} 
posted @ 2019-08-20 10:38  fashpoint  阅读(296)  评论(0编辑  收藏  举报