CSP2022题解之 PJ T4
好吧,好一道 dp 题。
考虑发现,不管坐标们长啥样,最后的结果肯定是
所以考虑建图。将每两个可以通过放置中间节点到达的点进行连边,然后跑最长路即可。
但是又发现,我们连出的图是一个 Dag。(很明显)
所以甚至我们可以直接记忆化搜索找出最长路。
因为是 PJ T4,所以放出考场代码:
#include<bits/stdc++.h>
using namespace std;
int n,k;
const int Maxn=610;
const int Maxk=110;
const int Maxm=2e5+10;
int head[Maxn],tot;
struct Edge{
int to;
int w;
int nxt;
}E[Maxm<<1];
void addedge(int u,int v,int w)
{
tot++;
E[tot].to=v;
E[tot].w=w;
E[tot].nxt=head[u];
head[u]=tot;
}
struct Point{
int x,y;
}P[Maxn];
void check(int x,int y)
{
if(P[x].x>=P[y].x && P[x].y>=P[y].y)
{
if(abs(P[x].x-P[y].x)+abs(P[x].y-P[y].y)-1>k) return ;
if(abs(P[x].x-P[y].x)+abs(P[x].y-P[y].y)==1)
{
addedge(y,x,0);
}else{
addedge(y,x,abs(P[x].x-P[y].x)+abs(P[x].y-P[y].y)-1);
}
//cout<<y<<"->"<<x<<":"<<abs(P[x].x-P[y].x)+abs(P[x].y-P[y].y)-1<<endl;
}
}
int dp[Maxn][Maxn];
int dfs(int u,int rk) // rk 可供用的加点数量
{
if(dp[u][rk]!=-1) return dp[u][rk];
int res=1;
for(int i=head[u];i;i=E[i].nxt)
{
int v=E[i].to,w=E[i].w;
if(rk>=w)
{
//cout<<u<<":"<<v<<endl;
int tmp=dfs(v,rk-w)+w+1;
res=max(res,tmp);
}
}
dp[u][rk]=res;
return res;
}
int main()
{
//freopen("point.in","r",stdin);
//freopen("point.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&P[i].x,&P[i].y);
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j) continue;
check(i,j);
}
}
int ans=-0x3f;
memset(dp,-1,sizeof(dp));
for(int i=1;i<=n;i++)
{
//memset(dp,-1,sizeof(dp));
for(int j=0;j<=k;j++)
{
int tmp=dfs(i,j);
tmp+=(k-j);
//cout<<i<<":"<<j<<",tmp="<<tmp<<endl;
ans=max(ans,tmp);
}
}
printf("%d\n",ans);
return 0;
}
时间复杂度:
Q: 这题这么简单,为什么你做了 1 个小时
A: 因为我开始在进行搜索的时候,将 dp 数组重置成 -1 了……