2020年牛客算法入门课练习赛2(A dp ,B bfs ,C 贪心,E dp)

题目链接

A-古老的牛市,遗迹的天梯

做法:n只有200,简单dp,设dp[i]为到达i这个位置时的最小步数。

转移方程:j+k 从j+k这个点倒退k步然后一步到i

for(int j=i-1;j>=1;--j){

   for(int k=0;k<i-j&&k<41;++k){
       if(a[j]+f[k]>=a[i]){

             p[i]=min(dp[i],dp[j+k]+k+1);
             flag=1;
       }
    }
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

inline ll read()
{
	ll x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
	return w==1?x:-x;
}
const int N=2e2+10;
ll a[N],dp[N],f[N];
int n;
int main()
{
    f[0]=1;rep(i,1,40) f[i]=f[i-1]*2;

    n=read(); rep(i,1,n) a[i]=read(),dp[i]=1e14;


    dp[1]=0;
    for(int i=2;i<=n;++i){

        int flag=0;
        for(int j=i-1;j>=1;--j){

            for(int k=0;k<i-j&&k<41;++k){
                if(a[j]+f[k]>=a[i]){

                    dp[i]=min(dp[i],dp[j+k]+k+1);
                    flag=1;
                }
            }

        }


        if(!flag) {puts("-1");return 0;}
    }

    printf("%d\n",dp[n]);


}
/*
5
0 1 2 3 100
*/

B--几乎毁灭牛市的流星雨

做法:记录每个格子的陨石到达时间,简单bfs一下就可以了。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

inline ll read()
{
	ll x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
	return w==1?x:-x;
}
const int N=3e2+10,inf=0x3f3f3f3f;
int vs[N][N],m;
int dir[4][2]={1,0,0,1,-1,0,0,-1};
struct node
{
    int x,y,t;
};
int main()
{
    m=read();
    memset(vs,inf,sizeof(vs));
    while(m--)
    {
        int x=read(),y=read(),t=read();
        vs[x][y]=min(vs[x][y],t);
        rep(i,0,3)
        {
            int xx=x+dir[i][0],yy=y+dir[i][1];
            if(xx<0||yy<0||xx>300||yy>300) continue;
            vs[xx][yy]=min(vs[xx][yy],t);
        }
    }
    queue<node >que;
    que.push({0,0,0});
    while(que.size()){
        node now=que.front();que.pop();
        //printf("x:%d y:%d t:%d\n",now.x,now.y,now.t);
        if(vs[now.x][now.y]==inf) {
            printf("%d\n",now.t);return 0;
        }
        rep(i,0,3)
        {
            int xx=now.x+dir[i][0],yy=now.y+dir[i][1];
            if(xx<0||yy<0||xx>300||yy>300) continue;
            if(vs[xx][yy]<=now.t+1)continue;
            que.push({xx,yy,now.t+1});
        }
    }
}

C-迁徙过程中的河流

做法:经典两人坐船过河问题。就两种方案过河:

三个人的时候 a、b、c无论怎么过 最优都是a+b+c

四个人以上,每次运输完,保持左边至少有三个以上,且a、b在左边

假设a、b、y、z 从小到大排序  a是最小,b是大于a  那么就是:

ay   a   az  a

ab  a  yz  b

两个方案中取最小的就可以了。

#include<bits/stdc++.h>
using namespace std;
int n;
int a[100010];
int cal(int a, int b, int y, int z)
{
    return min(z + a + y + a, b + a + z+b);
}


void solve()
{
    int sum=0;
    int i=n-1;
    while(i>2)
    {
        int m=cal(a[0],a[1],a[i-1],a[i]);
        sum+=m;
        i-=2;
    }
    if (i==2)
        sum += a[0] + a[1] + a[2];
    else
        sum += a[1];
    printf("%d\n", sum);


}
int main()
{

    cin>>n;
    for(int i=0;i<n;i++)
    cin>>a[i];
    sort(a,a+n);


    if(n==1) cout<<a[0]<<endl;
    else solve();

}

E-牛牛的旅游纪念品

做法:三维dp ,dp[i][j][k] k==0||k==1  代表第i位数取或者不取,且已经取了j个数时的最大权值。

预处理:

dp[0][0][0]=dp[0][0][1]=0;
for(int i=1;i<=k;++i) dp[i][1][1]=a[i];

状态转移方程:

rep(i,1,n)
    {
        
        for(int j=min(i,m);j>=0;--j){
            dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]);
            dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][1]);
            if(i-k>=0&&j-1>=0){
 
                dp[i][j][1]=max(dp[i][j][1],dp[i-k][j-1][0]+a[i]);
                dp[i][j][1]=max(dp[i][j][1],dp[i-k][j-1][1]+a[i]);
            }
        }
    }

代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
 
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
 
inline ll read()
{
    ll x=0,w=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
    return w==1?x:-x;
}
const int N=1e4+10,M=1e2+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
int n,m,k;
ll dp[N][M][2];
int a[N];
int main()
{
    n=read(),m=read(),k=read();
    rep(i,1,n) a[i]=read();
 
    memset(dp,-inf,sizeof(dp));
 
    dp[0][0][0]=dp[0][0][1]=0;
    for(int i=1;i<=k;++i) dp[i][1][1]=a[i];
 
    rep(i,1,n)
    {
        
        for(int j=min(i,m);j>=0;--j){
            dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]);
            dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][1]);
            if(i-k>=0&&j-1>=0){
 
                dp[i][j][1]=max(dp[i][j][1],dp[i-k][j-1][0]+a[i]);
                dp[i][j][1]=max(dp[i][j][1],dp[i-k][j-1][1]+a[i]);
            }
        }
    }
 
    printf("%lld\n",max(dp[n][m][0],dp[n][m][1]));
    //printf("%lld %lld\n",dp[n][m][0],dp[n][m][1]);
 
}
/*
4 2 2
-2 -4 6 -1
*/

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/106728902
今日推荐