Week1

1.

题目背景

给定一个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

#include<stdio.h>
int n,m,t,sum=0;//N为行,M为列,T为障碍总数
int sx,sy,fx,fy,cx,cy;//起点坐标SX,SY,终点坐标FX,FY, 障碍坐标CX,CY
int a[6][6],book[6][6];
void dfs(int x,int y)
{
    int next[4][2]={{0,1},//向右
                    {1,0},//向下
                    {0,-1},//向左
                    {-1,0}};//向上

    if(x == fx&&y == fy)//到达终点
    {
        sum++;
        return;
    }

    int tx,ty,k;
    //枚举四种走法
    for(k=0;k<4;k++)
    {
        tx=x+next[k][0];
        ty=y+next[k][1];

        if(tx<1||ty<1||tx>n||ty>m)
            continue;
        if(a[tx][ty] == 0&&book[tx][ty] == 0)
        {
            book[tx][ty]=1;
            dfs(tx,ty);
            book[tx][ty]=0;
        }
    }
    return ;
}
int main()
{
    scanf("%d %d %d",&n,&m,&t);
    scanf("%d %d %d %d",&sx,&sy,&fx,&fy);
    int k=0;
    while(t--)
    {
        scanf("%d %d",&cx,&cy);
        a[cx][cy]=1;//标记障碍处
    }
    book[sx][sy]=1;//标记起点已经在路径中
    dfs(sx,sy);
    printf("%d",sum);
    return 0;
}

2.

题目描述

一个如下的 6 \times 66×6 的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5 来描述,第 ii 个数字表示在第 ii 行的相应位置有一个棋子,如下:

行号 1\ 2\ 3\ 4\ 5\ 61 2 3 4 5 6

列号 2\ 4\ 6\ 1\ 3\ 52 4 6 1 3 5

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 33 个解。最后一行是解的总个数。

输入格式

一行一个正整数 nn,表示棋盘是 n \times nn×n 大小的。

输出格式

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

输入输出样例

输入 #1复制

6

输出 #1复制

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

说明/提示

【数据范围】
对于 100\%100% 的数据,6 \le n \le 136≤n≤13。

题目翻译来自NOCOW。

USACO Training Section 1.5

#include<stdio.h>
int n,sum=0;//全局变量未初始化时默认为0
///不能全局定义col(开始被这个错误卡了好久)
int a[100],b[100],c[100],d[100];
///之所以不设置为13是因为对角线数远大于N,干脆都开大一些
void dfs(int row)
{
    if(row==n+1)//如果遍历到了第n+1行,则说明已经出了一组结果
    {
        if(sum<3)
        {
            for(int g=1; g<=n; g++)
            {
                printf("%d ",a[g]);
            }
            printf("\n");
        }
        sum++;
        return;
    }
    for(int col=1; col<=n; col++)//每一行从第一个位置开始遍历尝试
    {
        if((b[col] == 0)&&(c[row+col] == 0)&&(d[row-col+n] == 0))
        {
            a[row]=col;//记录皇后位置
            b[col]=1;
            c[row+col]=1;//这里
            d[row-col+n]=1;//和这里 就是标记了当前皇后所在位置的对角线被标记了
            //其中\对角线的表示之所以要加个n是yw有些情况row-col为负数,但数组下标不能为负数,所以这里整体右移n个单位使\对角线数组的下标为正
            dfs(++row);//进一步搜索!
            row--;
            ///这里不能用row++!!!!!!!
            b[col]=0;
            c[row+col]=0;
            d[row-col+n]=0;//这三行是在回溯
        }
    }
    return;
}
int main()
{
    scanf("%d",&n);
    dfs(1);
    printf("%d",sum);
    return 0;
}

3.

题目描述

任何一个大于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

#include<stdio.h>
int n,l,a[10];//n<=8
void dfs(int sum,int data)//sum表示当前总和,data表示本次调用函数sum需从data加起
{
    int i;
    if(sum == n)
    {
       for(i=0;i<l-1;i++)
        printf("%d+",a[i]);
       printf("%d\n",a[i]);//最后一个数后面没有加号
       return;//已经得到一组答案,回溯到上一步
    }
    if(sum > n)
        return;//超过了,不合适,回到上一步
    if(sum < n)
    {
        for(i=data; i<n; i++)//加的数从1开始遍历
        {
            a[l++]=i;
            dfs(sum+i,i);
            a[--l]=0;//回溯
        }
    }
    return;
}
int main()
{
    scanf("%d",&n);
    dfs(0,1);//sum起初是0,从加1开始
    return 0;
}

4.

题目描述

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.

///连通块问题
#include<stdio.h>
char a[101][101];//用于保存地图
int ans,n,m;
void dfs(int x,int y)
{
    //上下左右斜上方斜下方都要考虑!
    int next[9][2]={{0,0},{1,1},{-1,-1},{-1,1},{1,-1},{0,1},{1,0},{-1,0},{0,-1}};
    a[x][y]='.';//走过的地方标记为‘.’
    int dx,dy;
    for(int i=0; i<=8; i++)//搜索周围
    {
            dx=x+next[i][0];
            dy=y+next[i][1];
            if(dx>=0&&dx<=n&&dy>=0&&dy<m&&a[dx][dy]=='W')
            {
                dfs(dx,dy);
            }
    }
    return;
}
int main()
{
    //输入地图
    scanf("%d%d",&n,&m);
    for(int i=0; i<=n; i++)
    {
        scanf("%s",a[i]);//一次输入一行
    }

    for(int i=0; i<=n; i++)
    {
        for(int j=0; j<m; j++)
        {
            if(a[i][j]=='W') //遇到W开始遍历
            {
                dfs(i,j);
                ans++;
            }
        }
    }
    printf("%d",ans);
    return 0;
}

5.

题目背景

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\leq s_1,s_2,s_3,s_4\leq 201≤s1​,s2​,s3​,s4​≤20。

1\leq A_1,A_2,\ldots,A_{s_1},B_1,B_2,\ldots,B_{s_2},C_1,C_2,\ldots,C_{s_3},D_1,D_2,\ldots,D_{s_4}\leq601≤A1​,A2​,…,As1​​,B1​,B2​,…,Bs2​​,C1​,C2​,…,Cs3​​,D1​,D2​,…,Ds4​​≤60。

//本质:0/1背包问题
///把总时间的一半当作背包容量
///每个题的时间当成物体的质量
#include<stdio.h>
#include<string.h>
int max(int x,int y)
{
    return(x>=y?x:y);
}
int main()
{
    int k,i,j;
    int ans=0;
    int s[5];//储存各个科目题数
    int a[25];//储存各个题目所用时间
    int t[5]= {0}; //储存每个科目作业总时间
    int f[5]= {0}; //储存每个科目的最优处理时间
    int dp[25][2000];///tip:dp表最大宽度为20*60(想想为什么)
    for(k=1; k<=4; k++)
        scanf("%d",&s[k]);
    for(k=1; k<=4; k++)
    {
        memset(dp,0,sizeof(dp));//每操作一门科目要重新初始化dp表哦
        for(i=1; i<=s[k]; i++)///tip
        {
            scanf("%d",&a[i]);
            t[k]+=a[i];
        }

            //printf("%d\n",t[k]);//检查
            for(i=1; i<=s[k]; i++) //质量
            {
                for(j=1; j<=t[k]/2; j++) //总容量
                {
                    if(j<a[i])///tip(抽象:是判断能否装下当前物品)
                        dp[i][j]=dp[i-1][j];
                    else
                        dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i]]+a[i]);
                }
            }

            f[k]=t[k]-dp[s[k]][t[k]/2];//当前科目的最短时间为总时间减去dp时间
        //printf("本科目所用时间为%d\n",f[k]);
    }
    for(i=1; i<=4; i++)
        ans=ans+f[i];//把每一科的最优时间相加即得到结果
    printf("%d",ans);
    return 0;
}
  • 20
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值