每日总结之搜索1.3

目录

算法学习

1.水坑 

2.Perket 

3.皇后问题

刷题网站 

1.奖学金

2.乒乓球

3.串的处理 

算法学习

1.水坑 

P1596 [USACO10OCT]Lake Counting S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1596

输入输出样例

输入 #1复制

10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.

输出 #1复制

3

1.dfs参量:x,y(二维数组);

2.for循环:8个方向的选择;

3.剪枝干:标记+障碍+边界;

4.终止条件:无设置,遇到不是连通块自动停止搜索,if 剪枝干即为终止条件;

5.注意字符输入getchar();连通块四周均为w的为一个水坑;

 
#include<stdio.h>
char a[200][200];
int ans=0,book[200][200],n,m;
void dfs(int x,int y)
{
    book[x][y]=1;                              //标记
    int tx,ty;
    int bx[]= {-1,1,0,0,1,-1,-1,1};           //8个方向,九宫格;
    int by[]= {0,0,1,-1,1,-1,1,-1};
    for(int i=0; i<8; i++)
    {
        tx=x+bx[i];
        ty=y+by[i];

        if(tx<1||ty<1||tx>n||ty>m)continue;     //跳过边界
        if(a[tx][ty]=='W'&&book[tx][ty]==0)     //未标记和目标量
        {
            dfs(tx,ty);                         //搜索九宫格下一个方向;
        }
    }
    return ;
}
int main()
{
    scanf("%d %d",&n,&m);
    getchar();                              //前后scanf,getchar吸收回车
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            scanf("%c",&a[i][j]);
        }
        getchar();                         //前后scanf,getchar吸收回车
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            if(a[i][j]=='W'&&book[i][j]==0)//遇到w且没有被标记
            {
                dfs(i,j);                 //搜索九宫格附近w
                ans++;                   //水坑+1
            }
        }
    }
    printf("%d",ans);
}

2.Perket 

P2036 [COCI2008-2009#2] PERKET - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P2036

Perket 是一种流行的美食。为了做好 Perket,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。你有 nn 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 ss 和苦度 bb。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。

众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。

另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。

输入格式

第一行一个整数 nn,表示可供选用的食材种类数。

接下来 nn 行,每行 22 个整数 s_isi​ 和 b_ibi​,表示第 ii 种食材的酸度和苦度。

输出格式

一行一个整数,表示可能的总酸度和总苦度的最小绝对差。

输入输出样例

输入 #1复制

1
3 10

输出 #1复制

7


1.dfs参量设置:x,y分别为酸甜度数总和,step;

2.for设置:n种调料;

3.终止条件:step==n+1调料加完,在出口设置对所有组找最小值;

4.注意:回溯时标记和值均要还原;

 
#include<stdio.h>
#include<math.h>
int n,a[100],b[100];
int book[100],minn=1000000;
int min(int a,int b)               //找最小值min函数;
{
    return a<b?a:b;
}
void dfs(int x,int y,int step)    //n种食材,1种食材分别有x甜度调料,y苦度调料两种调料;
{
    if(step==n+1)                 //每种食材至少加1个调料,n种食材==n步steps;
    {
        minn=min(abs(x-y),minn);  //abs绝对值函数;
        return ;
    }
    for(int i=1;i<=n;i++)
    {
        if(book[i]==0)
        {
            x*=a[i];
            y+=b[i];             //计算甜度和苦度;
            book[i]=1;           //标记;
            dfs(x,y,step+1);     //进入下一层
            book[i]=0;           //取消标记;
            x/=a[i];             //全部还原现场,别漏;
            y-=b[i];
        }
    }
    return ;
}
int main()
{
    scanf("%d",&n);
   for(int i=1;i<=n;i++)
    {
         scanf("%d %d",&a[i],&b[i]);
    }
    dfs(1,0,1);                 //×从1开始,+从0开始,层数从1开始;
    printf("%d",minn);          //全局变量minn,值在函数中改变;

}

3.皇后问题

P1219 [USACO1.5]八皇后 Checker Challenge - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)


1.解题关键:横竖斜只有1个皇后;斜:横纵坐标之和,横纵坐标之差

2.dfs参数设置:step,不用调用每层x,y,不是迷宫探险类,只用check二维数组上每一点

3.for循环设置:check,n层每层皇后是否满足check;

4.终止条件:step==n+1;

#include<stdio.h>
int n,a[20];                 //i表示行,a[i]表示列;
int cnt=0;
int check(int x,int y)      //n皇后是否成立,check游戏标准:横竖斜仅有一个皇后;
{
    for(int i=1; i<=x; i++)         //无需讨论行==情况,每次放step都是一行一行放的
    {
        if(a[i]==y)return 0;       //皇后位置和其他皇后列==(×)
        if(i+a[i]==x+y)return 0;   //皇后位置和其他皇后对角线1(×)
        if(i-a[i]==x-y)return 0;   //皇后位置和其他皇后对角线2(×)
    }
    return 1;
}
void dfs(int step)         //表示第step个皇后放在何处
{
    if(step==n+1)          //dfs最后一层为输出
    {
        cnt++;             //解的个数
        if(cnt<=3)
        {
            for(int i=1; i<=n; i++)
            {
                printf("%d ",a[i]);     
                if(i%n==0)printf("\n");
            }

        }
        return ;
    }
    for(int j=1; j<=n; j++) //共1-8列
    {
        if(check(step,j))   //check第step行的皇后是否能放在j列上
        {
            a[step]=j;      //放在j列,标记;
            dfs(step+1);    //进入下一层,放下一个皇后;
            a[step]=0;     //取消标记
        }
    }
}
int main()
{
    scanf("%d",&n);
    dfs(1);              //第一层开始
    printf("%d",cnt);   
    return 0; 
}

刷题网站 

1.奖学金

问题 E: 谁拿了最多奖学金(JSU-ZJJ) - OJ (jsuacm.cn)http://jsuacm.cn/problem.php?cid=1684&pid=4

#include <stdio.h>
struct student
{
    char name[20];   //姓名
    int aveScore;     //期末平均成绩
    int classScore;   //班级议论成绩
    char leader;      //是否是学生干部
    char west;         //是否是西部学生
    int articles;     //论文次数
};
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        getchar();
        int sum=0;//奖金总数
        int max=0,k=0,i=0;//记录最多奖金数
        struct student stu[200];
        for(i=0; i<n; i++)
        {
            scanf("%s %d %d %c %c %d",stu[i].name,&stu[i].aveScore,&stu[i].classScore,&stu[i].leader,&stu[i].west,&stu[i].articles);
            //getchar();
        }
        for(i=0; i<n; i++)
        {
            int jiangjin=0;
            if(stu[i].aveScore>80 && stu[i].articles>=1)
                jiangjin+=8000;
            if(stu[i].aveScore>85 && stu[i].classScore>80)
                jiangjin+=4000;
            if(stu[i].aveScore>90)
                jiangjin+=2000;
            if(stu[i].aveScore>85 && stu[i].west == 'Y')
                jiangjin+=1000;
            if(stu[i].classScore>80 && stu[i].leader=='Y')
                jiangjin+=850;
            sum+=jiangjin;
            if(jiangjin>max)
            {
                max=jiangjin;
                k=i;//当前序号
            }
        }
        printf("%s\n%d\n%d\n",stu[k].name,max,sum);
    }
    return 0;
}

2.乒乓球

问题 F: 乒乓球 - OJ (jsuacm.cn)http://jsuacm.cn/problem.php?cid=1684&pid=5  字符串输入转为利用多组输入字符,遇到'E'则跳出输出循环   

#include <stdio.h>
#include <string.h>
int main()
{
    int a=0, b=0, len,t=0,i;
    char ans[65000],s;
    while(~scanf("%c",&s))             //多组输入
    {
        if(s=='E')break;
        ans[t++]=s;
    }
    len = strlen(ans);
    for (i = 0; i < len; i++)          //11分制
    {
        if (ans[i] == 'W') a++;
        else  if (ans[i] == 'L') b++;
        if ((a >= 11 && a - b >= 2 )||(b >= 11 && b - a >= 2) )
        {
            printf("%d:%d\n", a, b);
            a = 0, b = 0;             //重置
        }
    }
    printf("%d:%d\n", a, b);//输出没有打完的时候的比分
    puts("");
    a = 0, b = 0;                    //初始化

    for (i = 0; i < len ; i++)        //21分制
    {
        if (ans[i] == 'W') a++;
        else  if (ans[i] == 'L') b++;
        if ((a >= 21 && a - b >= 2)||(b >= 21 && b - a >= 2) )
        {
            printf("%d:%d\n", a, b);
            a = 0, b = 0;            //重置
        }
    }
    printf("%d:%d", a, b);//输出没有打完的时候的比分,还没有打则会输出0:0
}

3.串的处理 

问题 I: 串的处理 - OJ (jsuacm.cn)http://jsuacm.cn/problem.php?cid=1684&pid=8

#include <stdio.h>
#include <string.h>
int main()
{
    char ch[201];
    while(gets(ch)!=NULL)
    {
        int len=strlen(ch);
        int c[201]= {0},d[201]= {0};
        if(ch[0]>='a'&&ch[0]<='z')
            ch[0]-=32;                               //转化为大写,字符直接运算
        for(int i=1; i<len; i++)
        {
            if(ch[i]<='z'&&ch[i]>='a'&&ch[i-1]==' ') //分类讨论
            {
                ch[i]-=32;
            }
            if(ch[i]==' '&&ch[i-1]==' ')           //空格重复出现的时候
            {
                d[i]=1;                            //桶标记位置,只标记了一个
            }
            if(ch[i]<='z'&&ch[i]>='a'&&ch[i-1]<='9'&&ch[i-1]>='0')
            {
                c[i]=1;                            //桶标记位置
            }
            if(ch[i]<='9'&&ch[i]>='0'&&((ch[i-1]<='z'&&ch[i-1]>='a')||(ch[i-1]<='Z'&&ch[i-1]>='A')))
            {
                c[i]=1;                            //桶标记位置
            }
            for(int i=0; i<len; i++)            
            {
                if(c[i]==1)printf("_");            //输出标记点的特殊指令
                if(d[i]==1)continue;              //区别桶1桶2执行不同指令
            }
            printf("\n");
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值