标签:复杂 方向 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