- 题意:P3638
- 思路:n<=9很容易想到斯坦纳树,然后就dp[i][l][r]表示合并到i号二维点,已合并区间[l,r]的最小步数。
然后转移也和原来一样。注意这里spfa或dj会超,注意到边权为1,但是有多个源点,所以两个队列,一个存储初始,另一个存储更新,然后如果一个点进入过队列2或者入过且出过队,然后就不会再入队,这样复杂度也是O(n)。
ps.卡常技巧
- 代码:
#include<bits/stdc++.h>
using namespace std;
const int N=505;
const int M=N*N*4;
const int K=9;
char s[N][N];
int dp[N][N][4];
int up,p[N],inf=0x3f3f3f3f,f[K][K][N*N],nxt[M],head[N*N],to[M],ecnt,cc,n,w,h,dir[5][2]={{-1,0},{0,1},{1,0},{0,-1}};
int Id(int x,int y) {return (x-1)*h+y;}
void add_edge(int u,int v) {if(u==v)return;nxt[++ecnt]=head[u];to[ecnt]=v;head[u]=ecnt;}
void DP(int x,int y,int d) {
if(dp[x][y][d]!=-1)return;dp[x][y][d]=0;
if(s[x][y]=='x'||x<1||y<1||x>w||y>h) {dp[x][y][d]=Id(x-dir[d][0],y-dir[d][1]);return;}
if(s[x][y]=='C') {DP(x+dir[(d+1)%4][0],y+dir[(d+1)%4][1],(d+1)%4);dp[x][y][d]=dp[x+dir[(d+1)%4][0]][y+dir[(d+1)%4][1]][(d+1)%4];return;}
else if(s[x][y]=='A') {DP(x+dir[(d+3)%4][0],y+dir[(d+3)%4][1],(d+3)%4);dp[x][y][d]=dp[x+dir[(d+3)%4][0]][y+dir[(d+3)%4][1]][(d+3)%4];return;}
int u=x+dir[d][0],v=y+dir[d][1];
DP(u,v,d);dp[x][y][d]=dp[u][v][d];
}
bool in_s[N*N],_kk[N*N];
int h1,t1,h2,t2,Q1[N*N],Q2[N*N];
vector<int>V[M];
struct node {int p,w;}tmp[N*N];
bool cmp(node u,node v) {return u.w<v.w;}
void DJ(int x,int y) {
h1=h2=1,t1=t2=0;
cc=0;int mx=0;
for(int i=1;i<=up;i++) {
if(f[x][y][i]>up)continue;
tmp[++cc]=(node){i,f[x][y][i]};
mx=max(mx,f[x][y][i]);
}
if(cc*10>mx) {
for(int i=1;i<=cc;i++) V[tmp[i].w].push_back(tmp[i].p);
for(int i=0;i<=mx;i++)
if(V[i].size()) {
for(int j=0;j<V[i].size();j++) Q1[++t1]=V[i][j];
V[i].clear();
}
}
else {
sort(tmp+1,tmp+1+cc,cmp);
for(int i=1;i<=cc;i++) Q1[++t1]=tmp[i].p;
}
while(1) {
int u=0,q=0;
if(h1<=t1) u=Q1[h1];
if(h2<=t2) q=Q2[h2];
else if(!u) break;
if(f[x][y][u]<f[x][y][q]) {
h1++; if(_kk[u])continue;
}
else {h2++;u=q;_kk[u]=1;}
for(int i=head[u];i;i=nxt[i]) {
int v=to[i],w;
if(in_s[v])continue;
w=f[x][y][u]+1;
if(f[x][y][v]>w) {
f[x][y][v]=w;
Q2[++t2]=v;in_s[v]=1;
}
}
}
for(int i=1;i<=h*w;i++) in_s[i]=_kk[i]=0;
}
void solve() {
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++) {
f[i-1][i-1][p[i]]=0;
}
for(int len=1;len<=n;len++) {
for(int i=0,tt=n-len;i<=tt;i++) {
int j=i+len-1;
for(int u=1;u<=up;u++) {
for(int mid=i;mid<j;mid++) {
f[i][j][u]=min(f[i][j][u],f[i][mid][u]+f[mid+1][j][u]);
}
}
DJ(i,j);
}
}
int ans=inf;
for(int i=1;i<=h*w;i++) ans=min(ans,f[0][n-1][i]);
if(ans==inf) printf("-1");
else printf("%d",ans);
}
int main() {
memset(dp,-1,sizeof(dp));
scanf("%d%d%d",&n,&h,&w);up=h*w;
for(int i=1;i<=w;i++) scanf("%s",s[i]+1);
int cc=0;
for(int i=1;i<=w;i++) for(int j=1;j<=h;j++) {
if(s[i][j]=='x') continue;
if(s[i][j]>='1'&&s[i][j]<='9') p[s[i][j]-'0']=Id(i,j);
for(int d=0;d<4;d++) {
DP(i,j,d);
if(dp[i][j][d])add_edge(Id(i,j),dp[i][j][d]);
}
}
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人