ACM训练

8/3 星期一 晴

今天又是dp的一天,果然dp的思想还是不能一下子就能理解,关于状态转移方程和决策这方面虽然说我能够看懂,但是还是需要更深层次的去探究。书上面的内容比较难懂啊,需要更多得去吃透。
不过今天做了一道dp得题目,思想还是比较容易 洛谷P2196 挖地雷
思路:最终是要求出最多的地雷数,并且还要回溯找到路线。之前看LIS问题的时候看见一个大佬的博客,上面有关于回溯的方法。所以我在做这题的时候就用了这个

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=25;
int pre[maxn],dp[maxn]={0},road[maxn][maxn],a[maxn],k=0,n,pos,Max=0;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i],dp[i]=a[i],pre[i]=i;
    for(int i=1;i<=n-1;i++)
      for(int j=i+1;j<=n;j++)
        cin>>road[i][j];
    ///找到挖最多地雷地窖的路,用dp去找出线路
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            if(road[i][j])              ///如果更够走到该地窖
            {
                dp[j]=max(dp[j],dp[i]+a[j]);
                if(Max<dp[j]) Max=dp[j];
                if(dp[j]==dp[i]+a[j])   ///更新地窖位置,pre数组用来装入之前地窖的位置
                {
                    pos=j;
                    pre[j]=i;
                }
            }
            else if(Max<dp[j])        ///如果不能走则判断该地窖的地雷数是否大于Max
                pos=j,Max=dp[j];
        }
    }
    Max=0;
    for(int i=1;i<=n;i++)
        if(dp[i]>Max)
        {
            pos=i;
            Max=dp[i];
        }
    a[k++]=pos;
    for(int i=pos;pre[i]!=i;i=pre[i])
        a[k++]=pre[i];
    for(int i=k-1;i>=0;i--)
        cout<<a[i]<<" ";
    cout<<endl;
    cout<<dp[pos];
    return 0;
}

PS:其中在进行状态转移方程的时候,还是有问题的(关于回溯这方面用的还是太少了)。整体方面题目不是很难,但是在能否走通下一个地窖这里,我没有考虑周全。比如有一个地窖什么都不通但是地雷数却非常大,那么就得选这个地窖,所以还是得多加思考


8/4 星期二 晴

动态规划果然还是需要很多前置知识的,看到后面很多地方都需要一些前置知识。比较难去看懂算法书而且题目一点思路都没有,转头去写搜索dfs题单去了。关于dfs问题,还是得先去看它的特点 今天做了一道题 洛谷P1135奇怪的电梯

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=200+5;
int a[N],n,A,B,flag=0,vis[N];
long long cnt=1e+9;
int dfs(int floor,long long sum)
{
    if(sum>ans) return;  ///TLE
    if(floor==B) {cnt=min(cnt,sum);flag=1;return 0;}
    vis[floor]=1;    ///表示此楼层已经到达过
    if(floor+a[floor]<=n&&!vis[floor+a[floor]])   ///如果电梯不会回到原来的层数
        dfs(floor+a[floor],sum+1);
    if(floor-a[floor]>=1&&!vis[floor-a[floor]])   ///同理
        dfs(floor-a[floor],sum+1);
    vis[floor]=0;     ///回溯
}
int main()
{
    scanf("%d%d%d",&n,&A,&B);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    dfs(A,0);
    if(flag)
        cout<<cnt;
    else
        cout<<-1;
    return 0;
}

PS:题目的难度不难,TLE的点以及电梯会不会回到原来的楼层是一个主要解决的问题。还是得多去思考一下!


8/6 星期四 晴

还是在学习dfs,感觉做其他题目的时候都需要dfs搜索,所以今天做了之前看了但是没有思路的题目 洛谷P1036 选数
主要就是素数的判别还有这题对选数的顺序要求不高。

#include<iostream>
#include<cmath>
using namespace std;
int n,k,a[25],cnt=0,vis[25];
bool is_prime(int t) ///判断素数
{
    if(t==1||t==0) return false;
    if(t==2) return true;
    for(int i=2;i<=sqrt(abs(t));i++)
       if(t%i==0)
         return false;
    return true;
}
void dfs(int now,int x,int sum)
{
    if(x==k)
    {
        if(is_prime(sum))
            cnt++;
    }
    else
    {
        for(int i=now;i<=n;i++)
        {
            if(vis[i]==1) continue;  ///如果已经被选中,跳过此数
            vis[i]=1;
            dfs(i+1,x+1,sum+a[i]);   ///选择此数
            vis[i]=0;                ///回溯,不选择此数
        }
    }
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    dfs(1,0,0);
    cout<<cnt;
    return 0;
}

8/7 星期五 晴

今天做了一道类似于跳马的题目,一直再调试数据改BUG,还是在dfs时候如何防止爆栈出了问题,还是得注意栈的问题。从找每次跳马所需的最小值到如何防止爆栈这期间,真的是头皮发麻。还是得注意爆栈的问题,要有好的限制条件才行!!以后要注意这些
洛谷P1443 马的遍历

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=405;
int N,M,sx,sy,vis[maxn][maxn];
void dfs(int x,int y,int step)
{
    if(x==sx&&y==sy&&step!=1)
        return ;
    if(step>200) return ;
    if(x-2>=1&&y-1>=1)
    {
        if(vis[x-2][y-1]==-1||vis[x-2][y-1]>step) ///我想到了这一点,但是不知道怎么去写
         {
         vis[x-2][y-1]=step;
         dfs(x-2,y-1,step+1);
         }
    }/// x-2,y-1
    if(x-1>=1&&y-2>=1)
    {
        if(vis[x-1][y-2]==-1||vis[x-1][y-2]>step)
         {
          vis[x-1][y-2]=step;
          dfs(x-1,y-2,step+1);
         }
    }/// x-1,y-2
    if(x-2>=1&&y+1<=M)
    {
         if(vis[x-2][y+1]==-1||vis[x-2][y+1]>step)
         {
           vis[x-2][y+1]=step;
           dfs(x-2,y+1,step+1);
         }
    }/// x-2,y+1
    if(x-1>=1&&y+2<=M)
    {
         if(vis[x-1][y+2]==-1||vis[x-1][y+2]>step)
         {
             vis[x-1][y+2]=step;
         dfs(x-1,y+2,step+1);
         }
    }/// x-1,y+2
    if(x+2<=N&&y-1>=1)
    {
        if(vis[x+2][y-1]==-1||vis[x+2][y-1]>step)
         {
             vis[x+2][y-1]=step;
         dfs(x+2,y-1,step+1);
         }
    }/// x+2,y-1
    if(x+1<=N&&y-2>=1)
    {
        if(vis[x+1][y-2]==-1||vis[x+1][y-2]>step)
         {
             vis[x+1][y-2]=step;
          dfs(x+1,y-2,step+1);
         }
    }/// x+1,y-2
    if(x+2<=N&&y+1<=M)
    {
         if(vis[x+2][y+1]==-1||vis[x+2][y+1]>step)
          {
              vis[x+2][y+1]=step;
          dfs(x+2,y+1,step+1);}
    }/// x+2,y+1
    if(x+1<=N&&y+2<=M)
    {
        if(vis[x+1][y+2]==-1||vis[x+1][y+2]>step)
         {
             vis[x+1][y+2]=step;
         dfs(x+1,y+2,step+1);
         }
    }/// x+1,y+2
}
int main()
{
    scanf("%d%d%d%d",&N,&M,&sx,&sy);
    for(int i=1;i<=N;i++)
     for(int j=1;j<=M;j++)
         vis[i][j]=-1;
    vis[sx][sy]=0;
    dfs(sx,sy,1);
    for(int i=1;i<=N;i++)
     {
         for(int j=1;j<=M;j++)
            printf("%-5d",vis[i][j]);
         cout<<endl;
     }
    return 0;
}

今天还做了一道迷宫,之前在B站看视频的时候看到了关于迷宫dfs问题。我觉得很有意思然后在洛谷里面找了迷宫题刷了一下,有了这种思想果然还是挺简单的,但是自己还是犯了一个错误
洛谷P1605

#include<iostream>
using namespace std;
int N,M,n,vis[6][6]={0},ban[6][6]={0},sx,sy,fx,fy,sum=0;
void dfs(int x,int y)
{
    if(x==fx&&y==fy)
    {
        sum++; return ;
    }
     if(vis[x][y+1]==0&&ban[x][y+1]!=1&&y+1<=M)  ///向右搜索路径
    {
        vis[x][y+1]=1;                      
        dfs(x,y+1);
        vis[x][y+1]=0;  ///回溯
    }
      if(vis[x+1][y]==0&&ban[x+1][y]!=1&&x+1<=N) ///向下
    {
        vis[x+1][y]=1;
        dfs(x+1,y);
        vis[x+1][y]=0;
    }
      if(vis[x][y-1]==0&&ban[x][y-1]!=1&&y-1>=1) ///向左
    {
        vis[x][y-1]=1;
        dfs(x,y-1);
        vis[x][y-1]=0;
    }
      if(vis[x-1][y]==0&&ban[x-1][y]!=1&&x-1>=1)   ///向上
    {
        vis[x-1][y]=1;
        dfs(x-1,y);
        vis[x-1][y]=0;
    }
    return ;
}
int main()
{
    cin>>N>>M>>n;
    cin>>sx>>sy>>fx>>fy;
    for(int i=1;i<=n;i++)
    {
        int t,f;
        cin>>t>>f;
        ban[t][f]=1;
    }
    vis[sx][sy]=1;  ///因为这里没有加所以wa了,这种错误不能再犯了
    dfs(sx,sy);
    cout<<sum;
}

PS:关于递归dfs这类问题,一定要注意爆栈和TLE的问题。限制条件也得认真去想,而不是一股脑的去写。我得更加多学习和改正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值