大法师(简单题总结)

第一题:吃奶酪

它也有两个小剪枝

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;
}

第六题:海战

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

于是,真香

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

不是矩形一定会这样的景象:
o_1566215036200.pngo_1566215153334.png
o_1566215216068.pngo_1566215245662.png

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

所以得出:如果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;
} 

转载于:https://www.cnblogs.com/fashpoint/p/11381511.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值