锻炼身体
根据题目意思可以得出,这个蔡老板的走法就是走‘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;
}