标签:复杂 方向 can 元素 mask 合成 训练指南 sla 区分
https://vjudge.net/problem/UVA-1408
有个很神奇的雷达,可以得到当前时刻$n\times m$格里面的飞机的能量。每个格子里面任何时间都只会有1架飞机。格子里面的能量反映了飞机的轨迹,飞机是按照能量递减的方向飞行的,只能沿着横向或纵向飞行,并且中途不能改变方向。如果能量为0,表示这个格子里面没有飞过飞机。给出当前的能量图,问从这张图里面能输出最少多少架飞机。
$1\leqslant n\leqslant 50, 1\leqslant m\leqslant 9$
3 3 1 2 3 4 5 6 7 8 9 0 0
Case 1: 3
训练指南说这是一道入门题= =然后发现我状态设的很差
一开始设状态为当前格子放“<”“>”“^”“v”四种或不放,时间复杂度$5^{n\times m}\times 8$(开头和继续)
然后就不知道怎么优化了
实际上可以剪枝
把开头、不放全部合成成1个“o”,横向“<”“>”合成成“-”,纵向“^”“v”合成成“|”
为了区分继续的方向,可以对三个元素进行判断(这个时候一定有三个元素)
还有一个问题是一个开头只能用一次,不能横向和纵向都接上,因此接纵向的时候判断右边没有接上横向就可以了
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cctype> #include<unordered_map> #define REP(i,a,b) for(register int i=(a); i<(b); i++) #define REPE(i,a,b) for(register int i=(a); i<=(b); i++) #define PERE(i,a,b) for(register int i=(a); i>=(b); i--) using namespace std; typedef long long ll; int nrow, ncol; unordered_map<unsigned, int> dp[57][9]; int mp[57][9]; int kase=0; inline unsigned setmask(unsigned k, int v, int d) { unsigned msk=7<<(v*3); k &= ~msk; k |= d<<(v*3); return k; } inline unsigned getmask(unsigned k, int v) { return (k>>(v*3))&7; } inline bool can(int a, int b, int c) { if(a<b && b<c) return true; if(a>b && b>c) return true; return false; } int calc(int r, int c, unsigned F) { if(c==ncol) {r++; c=0;} if(r==nrow) return 0; if(mp[r][c]==0) return calc(r, c+1, setmask(F, c, 0)); if(dp[r][c].count(F)) return dp[r][c][F]; int ans=0x3f3f3f3f; ans = 1+calc(r, c+1, setmask(F, c, 0)); if(c && mp[r][c-1]) { unsigned t=getmask(F,c-1); if(t==0 && mp[r][c-1]!=mp[r][c]) { ans = min(ans, calc(r, c+1, setmask(F, c, 1))); } else if(t==1 && can(mp[r][c-2], mp[r][c-1], mp[r][c])) { ans = min(ans, calc(r, c+1, setmask(F, c, 1))); } } if(r && getmask(F,c+1)!=1 && mp[r-1][c]) { unsigned t=getmask(F,c); if(t==0 && mp[r-1][c]!=mp[r][c]) { ans = min(ans, calc(r, c+1, setmask(F, c, 2))); } else if(t==2 && can(mp[r-2][c], mp[r-1][c], mp[r][c])) { ans = min(ans, calc(r, c+1, setmask(F, c, 2))); } } dp[r][c][F]=ans; return ans; } int main() { while(~scanf("%d%d", &nrow, &ncol) && nrow) { REP(i,0,nrow) REP(j,0,ncol) { scanf("%d", &mp[i][j]); } REP(i,0,nrow) REP(j,0,ncol) dp[i][j].clear(); int ans=calc(0,0,0); kase++; printf("Case %d: %d\n", kase, ans); } return 0; }
标签:复杂 方向 can 元素 mask 合成 训练指南 sla 区分
原文地址:https://www.cnblogs.com/sahdsg/p/12325516.html