P2905 [USACO08OPEN]农场危机Crisis on the Farm-dp

本文深入探讨了使用动态规划(DP)解决路径寻找问题的方法,特别是在寻找最大值和字典序最小路径时的策略。通过具体实例,展示了如何在考虑步数作为阶段的DP过程中,有效地利用四个方向的转移来解决问题。文章还提供了代码实现细节,包括状态转移方程和边界条件的设定。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

dp,阶段就是步数。

本蒟蒻想不出来,只好用题解大法:四个方向的走路,dp的阶段是步数,每个点可以由四个方向转移而来。这是逆序做的。他这样做的好吃是最后回到原点,然后逆序找字典序最小即可。

独立思考下,如果从原点出发,那么向四个方向走,需要找出最大值和字典序最小的路径。因此,对每个点,值变化的时候更新值,值不变但路径更小的时候也更新。

#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
const int N=1000,T=31;
const int dx[]={1,0,0,-1},dy[]={0,1,-1,0}; 
string d="ENSW";
//方向增量按字母字典序的顺序给出:E,N,S,W
int n,m,k,i,j,s,t,x[N],y[N],p[N],q[N],g[T*2][T*2],f[T][T*2][T*2],u,v,ans=0;
int ew[70],ns[70],Tk;
string st[T][T*2][T*2]; 
string minst="Z";
//因为下标不能为负,所以向南向西的负数要加上T使之为正
int max(int x,int y){return x>y?x:y;}
int abs(int x){return x>0?x:-x;}
int main(){
	for(int i=1;i<T;i++)
		for(int j=0;j<2*T;j++) 
				for(int k=0;k<2*T;k++)st[i][j][k]+='Z';
    scanf("%d%d%d",&n,&m,&k);
	Tk=	k+1;
    for(i=0;i<n;i++)
        scanf("%d%d",x+i,y+i);
    for(i=0;i<m;i++)
        scanf("%d%d",p+i,q+i);
    for(i=0;i<n;i++)
        for(j=0;j<m;j++)
            if(abs(p[j]-x[i])+abs(q[j]-y[i])<=k)
                g[p[j]-x[i]+Tk][q[j]-y[i]+Tk]++;
    for(t=0;t<k;t++)
        for(u=Tk-t;u<=Tk+t;u++)
			for(v=Tk-t;v<=Tk+t;v++){
				if(abs(u-Tk)+abs(v-Tk)>t)continue;				
				for(int i=0;i<4;i++){
					if(f[t+1][u+dx[i]][v+dy[i]]<f[t][u][v]+g[u+dx[i]][v+dy[i]]){
						f[t+1][u+dx[i]][v+dy[i]]=f[t][u][v]+g[u+dx[i]][v+dy[i]];
					    st[t+1][u+dx[i]][v+dy[i]]=st[t][u][v]+d[i];
						}
					else if(f[t+1][u+dx[i]][v+dy[i]]==f[t][u][v]+g[u+dx[i]][v+dy[i]]&&
						 st[t+1][u+dx[i]][v+dy[i]]>st[t][u][v]+d[i])
						 st[t+1][u+dx[i]][v+dy[i]]=st[t][u][v]+d[i];
					ans=max(ans,f[t+1][u+dx[i]][v+dy[i]]);
				}								   
			}
	 for(u=Tk-t;u<=Tk+t;u++)
			for(v=Tk-t;v<=Tk+t;v++)
			    if(f[k][u][v]==ans)minst=min(minst,st[k][u][v]);
	cout<<ans<<endl<<minst<<endl; 
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值