暑期集训2q11(暑假终章)

锻炼身体

在这里插入图片描述
根据题目意思可以得出,这个蔡老板的走法就是走‘L’形状,我们可以用两个增量数组存一下表示往那里走,然后BFS就好
1.增量数组:
dx[1]=p;dy[1]=qq;//右下
dx[2]=-p;dy[2]=qq;//右上
dx[3]=-p;dy[3]=-qq;//左上
dx[4]=p;dy[4]=-qq;//左下
dy[5]=p;dx[5]=qq;另外的‘L形状
dy[6]=-p;dx[6]=qq;
dy[7]=-p;dx[7]=-qq;
dy[8]=p;dx[8]=-qq;
2.找到答案就输出,BFS模板,起点入队。3起点,4终点,0/2赋值为障碍

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    long long f=1,res=0;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
    return res*f;
}
struct node
{
    int x;
    int y;
    int tep;
};
int n,m,p,qq,stx,sty,enx,eny;
int dx[8];
int dy[8];
int root,a[35][35],vis[35][35];
queue<node>q;
int main()
{
    n=read();m=read();p=read();qq=read();
    //增量数组
    dx[1]=p;dy[1]=qq;
    dx[2]=-p;dy[2]=qq;
    dx[3]=-p;dy[3]=-qq;
    dx[4]=p;dy[4]=-qq;
    dy[5]=p;dx[5]=qq;
    dy[6]=-p;dx[6]=qq;
    dy[7]=-p;dx[7]=-qq;
    dy[8]=p;dx[8]=-qq;
     
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            a[i][j]=read();
            //预处理起点和地图
            if(a[i][j]==3)a[i][j]=1,stx=i,sty=j;
            if(a[i][j]==4)a[i][j]=1,enx=i,eny=j;
            if(a[i][j]==2||a[i][j]==0)a[i][j]=0;
        }
    }
    node st;st.x=stx;st.y=sty;st.tep=0;
    vis[st.x][st.y]=1;
    q.push(st);
    //模板BFS
    while(!q.empty())
    {
        node k=q.front();
        q.pop();
        if(k.x==enx&&k.y==eny)
        {
            cout<<k.tep;
            return 0;
        }
        for(int i=1;i<=8;i++)
        {
            int xx=k.x+dx[i];
            int yy=k.y+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m)
            {
                if(a[xx][yy]&&!vis[xx][yy])
                {
                    vis[xx][yy]=1;
                    node ne;ne.x=xx;ne.y=yy;ne.tep=k.tep+1;
                    q.push(ne);
                }
            }
        }
    }
    return 0;
}
  


管理部门

在这里插入图片描述
遍历有根树,把1设为根,因为这是单向边,并且保证没有环,所以从root=1开始遍历,用ans[i]表示以i为根的树的节点的个数,自己管不到自己,所以if(ans[i]-1==k)那么可以

#include<bits/stdc++.h>
#define maxn 1000010 
using namespace std;
inline int read()
{
    long long f=1,res=0;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
    return res*f;
}
int n,k;
int head[maxn],tot,ans[maxn],du[maxn],num;
struct node
{
    int u;
    int v;
}edge[maxn];
inline void add(int x,int y)
{
    edge[++tot].u=head[x];
    edge[tot].v=y;
    head[x]=tot;
}
inline void  dfs(int x)//遍历
{
     
    for(int i=head[x];i;i=edge[i].u)
    {
        dfs(edge[i].v);
        ans[x]+=ans[edge[i].v];
    }
}
int main()
{
    n=read();k=read();
    for(int i=1;i<n;i++)
    {
        int x,y;x=read();y=read();
        du[x]++;
        add(x,y);
    }
    for(int i=1;i<=n;i++)ans[i]=1; 
    dfs(1);
    for(int i=1;i<=n;i++)
    if(ans[i]-1==k)num++;
    cout<<num;
    return 0;
}


圣诞树上得礼物

圣诞特别礼物挂在一棵圣诞树上,这棵树有n层,每层有一件礼物,每件礼物都有一个价值,有的礼物还有一些连结线,与下层的礼物相连,领取礼物的规则如下:任选一件礼物,它的下面如果有连结线,则可以继续取它连结的礼物,以此类推,直至取到没有连结线的礼物才结束,你如果是第一个去取,怎样取才能获得最大的价值呢?请你编一程序解决这一问题。

dp,设立状态dp[i]表示的是选到第i层的最大价值,答案就是dp[1—n]中的最大值。考虑转移,从第1个点到i-1,如果两个点右边,那么就可以考虑转移了,上一层加上这一层的礼物

#include<bits/stdc++.h>
#define maxn 150
using namespace std;
inline int read()
{
    long long f=1,res=0;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
    return res*f;
}
int n,edge[maxn][maxn],x,a[maxn],ans,dp[maxn];
string s;
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {  
       bool pd=0;
        getline(cin,s);int res=0;
        for(int j=0;j<s.size();j++)//万恶的读入
        {
            if(pd&&s[j]==' ')
            {
                edge[i][res]=1;
                res=0;
            }
            else if(s[j]==' '&&!pd){a[i]=res;pd=1;res=0;}
             if(isdigit(s[j])){res=(res<<1)+(res<<3)+(s[j]&15);}
        }
        if(res&&pd)edge[i][res]=1;
        else if(res&&!pd)a[i]=res;
    }
 
    for(int i=1;i<=n;i++)
    {
        dp[i]=a[i];
        for(int j=1;j<i;j++)
        {
            if(edge[j][i])
            dp[i]=max(dp[j]+a[i],dp[i]);//右边可以考虑转移
        }
    }
    for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
    cout<<ans;
    return 0;
}


鱼塘钓鱼

约翰 钓鱼h小时(1≤h≤16,h*12个单位时间,5分钟为一个单位时间),
有n个池塘(2≤n≤25),分布在一条直线上,依次为L1,L2,…,Ln,从池塘Li到池塘Li+1要花去约翰ti个单位时间。约翰出发点为L1。
约翰可以任选若干个池塘垂钓,并且在每个池塘他都可以呆上任意个单位时间。
每个池塘的鱼会越钓越少。池塘Li在第一个单位时间内能钓到的鱼为Fi(0≤Fi≤100),并且每过一个单位时间在单位时间内能钓到的鱼将减少一个常数di(0≤di≤100),现在请你编一个程序计算约翰最多能钓到多少鱼。

这里提供两种思路
大根堆,维护到第i个池塘中🐟最多的池塘,一次次地往🐟多的那个池塘钓鱼,每次钓鱼要改变池塘🐟的总数,钓鱼的时间是总时间加上走到这里的时间

#include<bits/stdc++.h>
#define maxn 25
using namespace std;
inline int read()
{
    long long f=1,res=0;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
    return res*f;
}
priority_queue<pair<int,int> > q;
int a[maxn],b[maxn],c[maxn],sum[maxn];
int n,h;
long long maxx;
int main()
{
	n=read();h=read();h*=12;
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=n;i++)b[i]=read();
	for(int i=1;i<n;i++)c[i]=read(),sum[i+1]+=sum[i]+c[i];

	for(int i=1;i<=n;i++)
	{
		int ft=h-sum[i];
		long long ans=0;
		for(int j=1;j<=i;j++)
		{
			pair<int,int>st;
			st.first=a[j];
			st.second=j;
			q.push(st);
		}
		while(ft>0&&!q.empty())//钓鱼最多的池塘
		{
			pair<int,int>k=q.top();
			q.pop();
			ans+=k.first;
			
			k.first-=b[k.second];
	
			if(k.first>0)q.push(k);
			ft--;
		}

		maxx=max(maxx,ans);
	}
	cout<<maxx;
	return 0;
}

动态规划dp[i][j]表示到第i个池塘钓j个单位时间的🐟的最大值,那么最多钓总时间-走到这里的时间,先把他更新为不钓鱼,然后在这里枚举钓鱼的时间,等差数列求出可以钓的🐟,然后max状态转移

#include<bits/stdc++.h>
#define maxn 25
using namespace std;
inline int read()
{
    long long f=1,res=0;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){res=(res<<1)+(res<<3)+(ch&15);ch=getchar();}
    return res*f;
}
int a[maxn],b[maxn],c[maxn],sum[maxn],dp[maxn][450];
int n,h;
int maxx=-0x7fffffff;
int main()
{
	n=read();h=read();h*=12;
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=n;i++)b[i]=read();
	for(int i=1;i<n;i++)c[i]=read(),sum[i+1]+=sum[i]+c[i];

    for(int i=1;i<=n;i++)
    {
    	for(int th=1;th<=h-sum[i];th++)
    	{
    		dp[i][th]=dp[i-1][th];
    		for(int j=0;j<=th;j++)
    		{
    			if(a[i]-b[i]*(j-1)>0)
    			{
    			int g=(j*(a[i]+(a[i]-b[i]*(j-1))))/2+dp[i-1][th-j];
    			dp[i][th]=max(dp[i][th],g);
				}

			}
		}
		
		maxx=max(maxx,dp[i][h-sum[i]]);
	}
	cout<<maxx;
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值