猫鼠两题:捉猫&&老鼠

一道抓猫,一道捕鼠。

抓猫

(D.pas/c/cpp)
【 题目描述】
流浪猫布满城市的每一个角落, 非常影响市容市貌, 作为城市聘请的抓猫者, 你有一种捕捉器, 一定可以捕捉到所有走到里面的猫, 更加幸运的是你有一个非常厉害的动物心理学家, 他可以预测猫在不同位置的行走方向(共有东、 西、 南、 北四种情况)为了节约经费, 问你最少需要多少个捕捉器才能把所有的猫都抓住。
【 输入格式】
输入第一行包含两个整数 N 和 M(1<=N,M<=1000),表示城市被划分成 N×M 的网格。 接
下来 N 行, 每行包含 M 个字符“ E”、“ W”、“ S”、“ N” 代表东、 西、 南、 北 4 个方向, 表示
当猫在该位置的行走方向, 保证猫不会走出城市区域。
【 输出格式】
输出一个整数表示最少需要的捕捉器数。
【 样例输入输出】
D.in D.out
3 4
SWWW
SEWN
EEEN
2
【 数据说明】
40% 1<=N,M<=4
100% 1<=N,M<=1000
【 样例说明】 捕鼠器放在( 3,4) 点和( 2,2) 点或( 2,3) 点。


猫可以在任意位置,但是他们会按照一定的顺序走动,所以他们肯定会走到一个终点,或者走成一个环。所以我们直接模拟他们的路径,将他们走过的路全部连通到一个集合里面,即可完成此题。
所以,此题有并查集,广搜,深搜等多种解法,我使用广搜写的,(广搜相对较为繁琐)。

#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int i,j,k,n,m,tot,ans,head,tail;
int vis[1005][1005];
char map[1005][1005];
struct node{
    int x,y;
}q[1000005];
int main()
{
    scanf("%d%d
",&n,&m);
    for(register int i=0;i<n;i++){
      for(register int j=0;j<m;j++){
        scanf("%c",&map[i][j]);if(j==m-1) char c=getchar();
      }
    }
    for(register int i=0;i<n;i++)
     for(register int j=0;j<m;j++){
        if(vis[i][j]==1) continue;
        head=0;tail=1;q[tail].x=i;q[tail].y=j;ans++;vis[i][j]=1;
        while(head<tail){
            head++;
            int u1=q[head].x,u2=q[head].y;
            if(map[u1][u2]=='S'&&vis[u1+1][u2]==0){
                q[++tail].x=u1+1;q[tail].y=u2;vis[u1+1][u2]=1;
             }
            if(map[u1][u2]=='W'&&vis[u1][u2-1]==0){
                q[++tail].x=u1;q[tail].y=u2-1;vis[u1][u2-1]=1;
             }
            if(map[u1][u2]=='N'&&vis[u1-1][u2]==0){
                q[++tail].x=u1-1;q[tail].y=u2;vis[u1-1][u2]=1;
            }
            if(map[u1][u2]=='E'&&vis[u1][u2+1]==0){
                q[++tail].x=u1;q[tail].y=u2+1;vis[u1][u2+1]=1;
            }
            if(vis[u1-1][u2]==0&&map[u1-1][u2]=='S'){
                q[++tail].x=u1-1;q[tail].y=u2;vis[u1-1][u2]=1;
            }
            if(vis[u1+1][u2]==0&&map[u1+1][u2]=='N'){
                q[++tail].x=u1+1;q[tail].y=u2;vis[u1+1][u2]=1;
            }
            if(vis[u1][u2-1]==0&&map[u1][u2-1]=='E'){
                q[++tail].x=u1;q[tail].y=u2-1;vis[u1][u2-1]=1;
            }
            if(vis[u1][u2+1]==0&&map[u1][u2+1]=='W'){
                q[++tail].x=u1;q[tail].y=u2+1;vis[u1][u2+1]=1;
            }
         }
     }
    printf("%d",ans);
    return 0;
}





老鼠

(mouse.pas/c/cpp)
【 题目描述】
最近小 h 家闹鼠灾, 弄得小 h 十分恼火。 为了解决老鼠的问题, 小 h 根据老鼠的特点
想出了一个方法。 假设小 h 的家是一个 n*n 的格子, 每个格子都有一定的食物, 数量在 0
到 100 之间, 经过观察, 老鼠的窝在( 1, 1) 的位置, 老鼠吃东西有个特点, 到哪个地方,
就把这个地方的食物都吃掉, 而且每次都比上一次吃的食物要多, 因此它们总会有个停止的
地方, 而且, 这些老鼠一次最多可以跳 k 格, 不过只能按 x 轴或 y 轴方向来跳。 现在, 小 h
给出食物的分布, 他想知道一只老鼠最多可以吃到多少食物。
【 输入格式】
第一行,n,(1<=n<=100),k,(0<=k<=n),表示 n*n 的格子, 老鼠一次最多跳 k 格。
接下来的 n 行, 每行 n 个数, 表示这个方格上的食物数量。
【 输出格式】
一个数, 表示一只老鼠最多可以吃到的食物。
【 样例输入输出】
mouse.in Mouse.out
in:3 1
1 2 5
10 11 6
12 12 7

out:37
【 样例解释】
(1,1)->(1,2)->(1,3)->(2,3)->(2,2)->(3,2)
1+2+5+6+11+12=37

这题数据范围是100(n) 所以整个棋盘点数100*100=10000个。
所以普通的搜索无法AC,所以此题要用记忆化搜索,(记忆化搜索,所以DP肯定是可以的,我写的就是DP)。
我的方法比较玄学。先将所有格子转化成一维数组,然后按米粒数从小到大排序。
因为我们从(1,1)开始走,所以将(1,1)赋值为有答案,答案为(1,1)的米粒数。
然后从米粒的大小扫,如果在当前米粒数的那行或那列有小于此格米粒数的格子,且
当个已被赋值成有值(初始化的时候只有(1,1)赋值成有值,所以可以确保从(1,1)
往后生成),则当前格子的总值就是那个格子的值加上本格子的米粒数。当然for一
行一列,要取一个叫max。最后for一遍整张图的值,取max,既是答案。
代码辅助理解:

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define C c=getchar()
using namespace std;
int j,k,n,m,tot,ans,top;
int f[105][105],r[105][105];
struct node{
    int x,y,num,tot;
}a[10005];
int cmp(node a,node b){
    if(a.num<b.num) return 1;
    else return 0;
}
int read(){
    char c;int x;while(C,c<'0'||c>'9');x=c-'0';
    while(C,c>='0'&&c<='9') x=x*10+c-'0';return x;
}
int maxn(int a,int b){return a>b?a:b;}
int minn(int a,int b){return a<b?a:b;}
int main()
{
    n=read();k=read();
    register int i,j;
    for(i=1;i<=n;i++)
     for(j=1;j<=n;j++){
        f[i][j]=read();
        a[++top].x=i;a[top].y=j;a[top].num=f[i][j];
     }
    sort(a+1,a+1+top,cmp);r[1][1]=f[1][1];
    for(i=1;i<=top;i++){
        if(a[i].num==f[1][1]) continue;
        for(j=maxn(a[i].x-k,1);j<=minn(a[i].x+k,n);j++)
        if(f[j][a[i].y]<a[i].num) a[i].tot=maxn(a[i].tot,a[i].num+r[j][a[i].y]);
        for(j=maxn(a[i].y-k,1);j<=minn(a[i].y+k,n);j++)
        if(f[a[i].x][j]<a[i].num) a[i].tot=maxn(a[i].tot,a[i].num+r[a[i].x][j]);
        if(a[i].tot!=a[i].num) r[a[i].x][a[i].y]=a[i].tot;   /*此部判断很重要,以为如果没有其他格子能走到此格,那此格就不能赋
值为有值。否则其他各会从此格生成,导致答案偏大。(当时我没注意这点,被坑成狗)。*/
    }
    for(i=1;i<=n;i++) 
     for(j=1;j<=n;j++) ans=maxn(ans,r[i][j]);
    if(ans==0) ans=f[1][1];
    printf("%d",ans);
    return 0;
}





原文地址:https://www.cnblogs.com/stevensonson/p/7612210.html