2022年1月9日学习总结

8:40~11:40

第一题:

P1605

迷宫

题目背景

给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过。给定起点坐标和终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案。在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。

题目描述

输入格式

第一行N、M和T,N为行,M为列,T为障碍总数。第二行起点坐标SX,SY,终点坐标FX,FY。接下来T行,每行为障碍点的坐标。

输出格式

给定起点坐标和终点坐标,问每个方格最多经过1次,从起点坐标到终点坐标的方案总数。

输入输出样例

输入 #1复制

2 2 1
1 1 2 2
1 2

输出 #1复制

1

说明/提示

【数据规模】

1≤N,M≤5

解题思路:直接使用dfs对每一种路径进行判断,若是能走到终点计数即可。注:一种方案走完了一定要回溯。

代码如下:

#include<stdio.h>
int n,m,t;
int sx,sy,fx,fy;
int a[100],b[100];
int vis[10][10]= {0};
int sum=0;
int dx[4]= {1,-1,0,0};
int dy[4]= {0,0,1,-1};

void dfs(int x,int y)
{
    if(x==fx&&y==fy)
        {sum++; return;}//走到终点就计数
    vis[x][y]=1;//当前这个位置极为1,表示经过了这个点
    for(int i=0; i<4; i++)//往上下左右四个方向走
    {
        int nx=x+dx[i];//下一步经过的点
        int ny=y+dy[i];
        if(nx>n||nx<1||ny>m||ny<1||vis[nx][ny]==1)//若走出地图或者有障碍物或者走过的地方就不搜索

            continue;
        dfs(nx,ny);
        vis[nx][ny]=0;//回溯
    }

}
int main()
{
    scanf("%d%d%d",&n,&m,&t);
    scanf("%d%d%d%d",&sx,&sy,&fx,&fy);
    for(int i=0; i<t; i++)
    {
        scanf("%d%d",a+i,b+i);
        vis[a[i]][b[i]]=1;//有障碍的地方记为1
    }
    dfs(sx,sy);
    printf("%d",sum);
}

第二题:

P2392

kkksc03考前临时抱佛脚

题目背景

kkksc03 的大学生活非常的颓废,平时根本不学习。但是,临近期末考试,他必须要开始抱佛脚,以求不挂科。

题目描述

这次期末考试,kkksc03 需要考 44 科。因此要开始刷习题集,每科都有一个习题集,分别有 s_1,s_2,s_3,s_4s1​,s2​,s3​,s4​ 道题目,完成每道题目需要一些时间,可能不等(A_1,A_2,\ldots,A_{s_1}A1​,A2​,…,As1​​,B_1,B_2,\ldots,B_{s_2}B1​,B2​,…,Bs2​​,C_1,C_2,\ldots,C_{s_3}C1​,C2​,…,Cs3​​,D_1,D_2,\ldots,D_{s_4}D1​,D2​,…,Ds4​​)。

kkksc03 有一个能力,他的左右两个大脑可以同时计算 22 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。

由于 kkksc03 还急着去处理洛谷的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。

输入格式

本题包含 55 行数据:第 11 行,为四个正整数 s_1,s_2,s_3,s_4s1​,s2​,s3​,s4​。

第 22 行,为 A_1,A_2,\ldots,A_{s_1}A1​,A2​,…,As1​​ 共 s_1s1​ 个数,表示第一科习题集每道题目所消耗的时间。

第 33 行,为 B_1,B_2,\ldots,B_{s_2}B1​,B2​,…,Bs2​​ 共 s_2s2​ 个数。

第 44 行,为 C_1,C_2,\ldots,C_{s_3}C1​,C2​,…,Cs3​​ 共 s_3s3​ 个数。

第 55 行,为 D_1,D_2,\ldots,D_{s_4}D1​,D2​,…,Ds4​​ 共 s_4s4​ 个数,意思均同上。

输出格式

输出一行,为复习完毕最短时间。

输入输出样例

输入 #1复制

1 2 1 3		
5
4 3
6
2 4 3

输出 #1复制

20

说明/提示

1≤s1​,s2​,s3​,s4​≤20。

1≤A1​,A2​,…,As1​​,B1​,B2​,…,Bs2​​,C1​,C2​,…,Cs3​​,D1​,D2​,…,Ds4​​≤60。

解题思路:直接用dfs暴力破解然后回溯求出每门科目的最少时间然后相加。

解题代码:

#include<bits/stdc++.h>
using namespace std;

int s[5];
int a[5][25];
int i,j;
int Left,Right;
int sum=0;
int mini;

void dfs(int x)//深度搜索暴力求出最少时间
{
    if(x>s[i])//次数大于这门课的题目时求出所用时间
    {
        mini=min(mini,max(Left,Right));//mini存最少时间
        return;
    }
    Left+=a[i][x-1];//使用左脑所用时间
    dfs(x+1);
    Left-=a[i][x-1];//回溯
    Right+=a[i][x-1];//使用右脑所用时间
    dfs(x+1);
    Right-=a[i][x-1];//回溯

}
int main()
{
    for(i=0; i<4; i++)
        scanf("%d",s+i);
    for(i=0; i<4; i++)
    {
        mini=100000;//mini赋值为100000防止第一次赋值出错
        Left=Right=0;
        for(j=0; j<s[i]; j++)
            scanf("%d",a[i]+j);
        dfs(1);
        sum+=mini;//时间累加入sum
    }
    printf("%d",sum);
    return 0;
}
 

13.30~15.30

听英语听力40分钟。

b站学习dfs算法1小时左右。

复习数学1小时左右。

16:30~18:00

继续做题ac了一个

第三题:

P1596

[USACO10OCT]Lake Counting S

题目描述

Due to recent rains, water has pooled in various places in Farmer John's field, which is represented by a rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water ('W') or dry land ('.'). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors. Given a diagram of Farmer John's field, determine how many ponds he has.

由于近期的降雨,雨水汇集在农民约翰的田地不同的地方。我们用一个NxM(1<=N<=100;1<=M<=100)网格图表示。每个网格中有水('W') 或是旱地('.')。一个网格与其周围的八个网格相连,而一组相连的网格视为一个水坑。约翰想弄清楚他的田地已经形成了多少水坑。给出约翰田地的示意图,确定当中有多少水坑。

输入格式

Line 1: Two space-separated integers: N and M * Lines 2..N+1: M characters per line representing one row of Farmer John's field. Each character is either 'W' or '.'. The characters do not have spaces between them.

第1行:两个空格隔开的整数:N 和 M 第2行到第N+1行:每行M个字符,每个字符是'W'或'.',它们表示网格图中的一排。字符之间没有空格。

输出格式

Line 1: The number of ponds in Farmer John's field.

一行:水坑的数量

输入输出样例

输入 #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

说明/提示

OUTPUT DETAILS: There are three ponds: one in the upper left, one in the lower left, and one along the right side.

解题思路:暴力dfs遇到'W'就计数一次,然后dfs,把水周围8个方向全部找一遍,遇到‘W’就把'W'变为‘.’,直到把这一摊水全部搜索完。注:输入格式调试了十多分钟,用%s输入也出现了错误,最后用cin解决了。

AC代码:

#include<bits/stdc++.h>
using namespace std;

const int max_n=110;
char mp[max_n][max_n];
int n,m;
bool vis[max_n][max_n]= {0};
int dx[10]={-1,-1,-1,0,0,0,1,1,1};//x的方向
int dy[10]={-1,0,1,-1,0,1,-1,0,1};//y的方向

void dfs(int x,int y)
{
    if(mp[x][y]=='W')
    {
        mp[x][y]='.';
        for(int i=0;i<9;i++)//向8个方向继续搜索
            dfs(x+dx[i],y+dy[i]);
    }
}
int main()
{
    int sum=0;
    scanf("%d%d",&n,&m);
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            cin>>mp[i][j];//用cin解决输入格式问题
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
        {
            if(mp[i][j]=='W')
            {
                sum++;//遇到了水就直接计数
                dfs(i,j);//通过dfs函数将i j周围的水全部记为旱地
            }
        }
    printf("%d",sum);
}
 

20:00~20:40

继续想八皇后那题,感觉可以先打表将不可能达到要求的先剔除,但是暂时无法代码实现。

附上昨天学习总结,A掉了一个题目,一个题目有一个样例没过。

第一题:

P2404

自然数的拆分问题

题目描述

任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。现在给你一个自然数n,要求你求出n的拆分成一些数字的和。每个拆分后的序列中的数字从小到大排序。然后你需要输出这些序列,其中字典序小的序列需要优先输出。

输入格式

输入:待拆分的自然数n。

输出格式

输出:若干数的加法式子。

输入输出样例

输入 #1复制

7

输出 #1复制

1+1+1+1+1+1+1
1+1+1+1+1+2
1+1+1+1+3
1+1+1+2+2
1+1+1+4
1+1+2+3
1+1+5
1+2+2+2
1+2+4
1+3+3
1+6
2+2+3
2+5
3+4

说明/提示

用回溯做。。。。

n\le 8n≤8

解题思路:从1开始进行dfs,然后回溯。注:不要输出n。

AC代码如下:

#include<stdio.h>
int n;
int sum;//sum为每次减去当前数字后的和
int x[15]={1};//最小的自然数为1
void print(int a)//打印此方案
{
    int i;
    for(i=1;i<a;i++)
        printf("%d+",x[i]);
    printf("%d\n",x[a]);
}

void dfs(int a)
{
    for(int i=x[a-1];i<=sum;i++)//i从上一次排列的数字开始搜索
    {
        if(i==n) continue;//防止输出n这个数字
        sum-=i;//减去当前这个数字
        x[a]=i;//将这个数字存入x数组
        if(sum==0) print(a);//当sum为0的时候,证明x数组里面已经存好本次排列 输出即可
        else dfs(a+1);//继续搜索
        sum+=i;//上一方案已经结束,回溯进行下一排列
    }
}

int main()
{
    scanf("%d",&n);
    sum=n;
    dfs(1);
    return 0;
}
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值