P7660 [COCI2014-2015#5] ZMIJA
题目大意:
一个
1.向当前方向前进一格;
2.向上移动一步,并调转当前方向。
一开始的方向是向右,到达一个格子时自动收集当前位置的金币,移动过程中不能离开网格图。
问收集完所有金币至少需要多少步?
思路:
贪心。
首先记录下每一行最左/最右的金币的位置,每次贪心地取完这一行的所有金币,
然后判断上一行最左/最右的金币是否在当前方向上,
如果是,就先往前走到那个位置上,然后再上去,否则就直接上去。
代码:
#include<bits/stdc++.h>
#define _ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ll long long
#define ull unsigned long long
using namespace std;
inline int read() {
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
inline bool isblock(const char &ch) {
return ch=='.'||ch=='J'||ch=='Z';
}
inline bool getblock() {
register char ch;
while(!isblock(ch=getchar()));
return ch=='J';
}
inline int sign(const int &x) {
if(x>0) return 1;
if(x<0) return -1;
return 0;
}
const int N=1001;
int cnt[N],pos[N][2],sum;
bool mp[N][N];
int main() {
const int n=read(),m=read();
rep(i,1,n) {
rep(j,1,m) {
mp[i][j]=getblock();
if(mp[i][j]) {
if(!pos[i][0]) pos[i][0]=j;
pos[i][1]=j;
cnt[i]++;
sum++;
}
}
}
int ans=0;
for(register int x=n,y=1,d=1;;x--,d=-d) {
if(mp[x][y]) {
cnt[x]--;
sum--;
}
while(cnt[x]) {
ans++;
y+=d;
if(mp[x][y]) {
cnt[x]--;
sum--;
}
}
if(!sum) break;
while(pos[x-1][(bool)~d]&&sign(pos[x-1][(bool)~d]-y)==d) {
y+=d;
ans++;
}
ans++;
}
cout<<ans;
return 0;
}
注明:
思路来自 skylee。