洛谷普及综练1/2

幻象迷宫

解题思路: 搜素题型,但是还是有细节需要优化,理解假如能走到之前走到过的环境相同的点

代码: 【借鉴】

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define MEM(arr,num) memset(arr,num,sizeof(arr))
#define FOR(i,l,r) for(int i(l);i < r;++i)
#define SIZE 1511
using namespace std;

char board[SIZE][SIZE];
bool map1[SIZE * 2][SIZE * 2], map2[SIZE][SIZE];
//map1表示有无走到过这个点,map2表示有无走到过映射点
int n, m, dn, dm;

bool dfs(int x,int y)
{
    if(x == -1)
    {
        if(dfs(dn - 1, y))return true;
        return false;
    }
    if(x == dn)
    {
        if(dfs(0, y))return true;
        return false;
    }
    if(y == -1)
    {
        if(dfs(x, dm - 1))return true;
        return false;
    }
    if(y == dm)
    {
        if(dfs(x, 0))return true;
        return false;
    }//上面四个if表示是否到边界,是就传送
    if(map1[x][y] || board[x % n][y % m] == '#')
    {
        return false;
    }//判断能不能走
    if(map2[x % n][y % m])
    {
        return true;
    }//判断这有没有走到这个点的映射
    map1[x][y] = true;
    map2[x % n][y % m] = true;
    //记录
    if(dfs(x + 1, y))return true;
    if(dfs(x - 1, y))return true;
    if(dfs(x, y + 1))return true;
    if(dfs(x, y - 1))return true;
    //遍历
    return false;
}

int main()
{
    while(cin >> n >> m)
    {
        dn = n * 2;
        dm = m * 2;
        int sx, sy;
        FOR(i, 0, n)
        {
            FOR(j, 0, m)
            {
                cin >> board[i][j];
                if(board[i][j] == 'S')
                {
                    sx = i;
                    sy = j;
                }
            }
        }//输入+找起点
        MEM(map1, 0);
        MEM(map2, 0);
        if(dfs(sx, sy))    printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}



解题思路:
后续:

链接: 传送门



创意吃鱼法

解题思路: 题型是dp+预处理,理解dp方程f[i][j]=min(f[i-1][j-1],min(s1[i][j-1],s2[i-1][j]))+1

代码: 【借鉴】

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<string>
#include<map>
typedef long long ll;
using namespace std;
int n,m,ans;
int a[2509][2509],f[2509][2509],s1[2509][2509],s2[2509][2509];//s1为横向,s2为纵向 
int main()
{
    cin>>n>>m;
    //第一遍左上——右下 
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        scanf("%d",&a[i][j]);
        if(!a[i][j])
        {
            s1[i][j]=s1[i][j-1]+1;
            s2[i][j]=s2[i-1][j]+1;
        }
        if(a[i][j])
        f[i][j]=min(f[i-1][j-1],min(s1[i][j-1],s2[i-1][j]))+1;
        ans=max(ans,f[i][j]);
    }
    //第二遍右上——左下 
    memset(f,0,sizeof(f)); 
    memset(s1,0,sizeof(s1));//数组置0 
    memset(s2,0,sizeof(s2)); 
    for(int i=1;i<=n;i++)
    for(int j=m;j>=1;j--)
    {
        if(!a[i][j])
        {
            s1[i][j]=s1[i][j+1]+1;
            s2[i][j]=s2[i-1][j]+1;
        }
        if(a[i][j])
        f[i][j]=min(f[i-1][j+1],min(s1[i][j+1],s2[i-1][j]))+1;
        ans=max(ans,f[i][j]);
    }
    cout<<ans<<endl;
    return 0;
}



贪婪的送礼者

解题思路: 用stl尝试一下此题

代码: 【借鉴】

#include<map>
#include<string>
#include<vector>
#include<iostream>
using namespace std;
int NP,money,num;
map<string,int> m;//存钱数 
vector<string> id;//存人名 
int main(){
    cin>>NP;
    string tmp;
    for(int i=1;i<=NP;i++){
        cin>>tmp;
        id.push_back(tmp);//人名加进数组里(为了最后有序输出) 
    }
    for(int i=1;i<=NP;i++){
        cin>>tmp>>money>>num;//人 钱 送的人数 
        if(money==0||num==0)continue;//不送礼的直接跳 
        m[tmp]-=money;//送走了这么多钱 
        m[tmp]+=money%num;//多的还回来 
        for(int j=1;j<=num;j++){
            cin>>tmp;
            m[tmp]+=money/num;//得到钱数 
        }
    }
    for(vector<string>::iterator i=id.begin();i!=id.end();i++)
        cout<<*i<<" "<<m[*i]<<endl;//遍历输出 
    return 0;
}



立体图

解题思路: 理解题意,想出思路比较重要,一、摆放顺序,二、坐标计算
代码: 【借鉴】

#include<stdio.h>
#include<iostream>
using namespace std;
const char Stick[6][8]=
{
    "..+---+",
    "./   /|",
    "+---+ |",
    "|   | +",
    "|   |/.",
    "+---+.."
};//单个方块 
int a[55][55];
char Paint[550][550];//画布 
inline void Draw(int x,int y)//涂鸦函数 
{
    int i,j;
    for(i=0;i<6;i++)
        for(j=0;j<7;j++)
            if(Stick[6-i-1][j]!='.')
                Paint[x-i][y+j]=Stick[6-i-1][j];//放置方块 
}
int main()
{
    int N,M,K(0),L,i,j,x,y;
    scanf("%d%d",&N,&M);
    L=4*M+2*N+1;//计算画布宽度 
    for(i=1;i<=N;i++)
        for(j=1;j<=M;j++)
        {
            scanf("%d",&a[i][j]);
            K=max(K,a[i][j]*3+2*(N-i+1)+1);//计算画布长度 
        }
    for(i=1;i<=K;i++)
        for(j=1;j<=L;j++)
            Paint[i][j]='.';//画布初始化 
    for(i=1;i<=N;i++)    
        for(j=1;j<=M;j++)
        {
            x=K-2*(N-i);
            y=2*(N-i)+4*(j-1)+1;//计算坐标 
            while(a[i][j]--)
            {
                Draw(x,y);//涂鸦 
                x-=3;//向上放 
            }
        }
    for(i=1;i<=K;i++)
    {
        for(j=1;j<=L;j++)
            printf("%c",Paint[i][j]);
        printf("\n");
    }//打印画布 
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值