남자가 어디로 갈지 예측


17

남자는 (0, 0)높이 h와 너비 가있는 도시의 북서쪽 모서리 에 산다 w. 매일 그는 국경을 집에서 산책 (?, w)이나 (h, ?). 다음 예에서 남자는 (3, 3)오늘 갑니다 .

(0, 0) +--+  +  +  . (0, 4)
          |         
       +  +--+--+  .
                |   
       +  +  +  +  .
                |   
(3, 0) .  .  .  .  . (3, 4)

남자는 각 지점에서 비트를 기록합니다 ( +위의 예에서). 그가 한 지점에 도달 할 때마다 비트가 있으면 1남쪽 으로 가고 그렇지 않으면 남쪽 으로갑니다 . 그가 떠난 후 비트가 뒤집 힙니다. 예를 들면 다음과 같습니다.

Day 1: 1--0  1  1    Day 2: 0  1  1  1    Day 3: 1--1--1--1--  Day 4: 0  0  0  0  
          |                 |                                         |           
       0  1--0  0           0  0  1  0           1  0  1  0           1--0  1  0  
             |              |                                            |        
       1  0  1--0           1--0  0  1           0  1  0  1           0  1--0  1  
                |              |                                            |     
Destination: (3, 3)  Destination: (3, 1)  Destination: (0, 4)  Destination: (3, 2)

도시의 크기와 사람의 기록이 주어지면 n며칠 후에 사람의 목적지를 계산하십시오 .

입력:

첫 번째 줄에서 세 개의 정수이다 h, w하고 n.

다음 h줄에는 w사람의 기록을 나타내는 정수가 있습니다.

h <= 1000, w <= 1000, n <= 1000000000

산출:

n며칠 후에 사람의 목적지를 나타내는 두 개의 정수 .

샘플 입력 :

3 4 3
1 0 1 1
0 1 0 0
1 0 1 0

샘플 출력 :

0 4

샘플 코드 :

#include <iostream>
using namespace std;
bool d[1000][1000];
int main(){
    int h, w, n;
    cin >> h >> w >> n;
    for(int i = 0; i < h; i++)
        for(int j = 0; j < w; j++)
            cin >> d[i][j];
    int i, j;
    while(n--)
        for(i = 0, j = 0; i < h && j < w;){
            bool &b = d[i][j];
            d[i][j] ? j++ : i++;
            b = !b;
        }
    cout << i << " " << j << endl;
}

채점 :

  • UTF-8에서 가장 낮은 바이트 수입니다.
  • 코드의 실행 시간이에 독립적 인 n경우 점수를 50 % 줄이십시오.
    • 하지 마십시오 단지 모든 10억일의 결과를 계산하거나 보너스를 얻을 수있는 유사 멍청한 짓을한다. 효율적인 알고리즘을 찾으십시오!

내가 이해하지 못하는 2 가지. 출력, 때로는 당신이하지 않는 다른 시간에 0 인덱스를 사용합니다. 어떻게 작동합니까? 국경 + 1과 같아야합니까? 두 번째는 점수를 매기는 두 번째 줄입니다. 그게 무슨 소리 야?
Teun Pronk

4 일째에 3,2를 출력해야합니까?
Teun Pronk

2
무슨 일 n이 있어도 내 코드가 모든 1000000000 일의 결과를 계산 한 다음 결과를 출력 n하면 -50 % 보너스를 계속받을 수 있습니까?
user12205

@ace 지금 당신은 그렇게 넣어, 그것은 이해가되지 않습니다? 고마워 : P
Teun Pronk

@TeunPronk 예. 그것은 내 잘못이야.
johnchen902

답변:


7

GolfScript, 52.5 (105 %, 보너스 50 %)

~](;(\((2$(1,*+\@/{]zip 0\{~@@+.2$!+2/\@+.2/\@[\1&]}%zip~@;}%\;[{.0=0=\1${{1>}%}{1>}if.{~}%}do;].1-,n@0-,

이 버전은 매우 효율적이며 값이 큰 경우에도 온라인 으로 테스트 할 수 있습니다 .

user2357112의 솔루션 과 비슷한 접근 방식을 사용합니다 .


1
설명을 요구하지 마십시오 ;-)이 짐승을 깨고 디버깅하지 않고는 그것을 바꿀 수조차 없습니다.
Howard

13

파이썬 2, 192 바이트 * 0.5 보너스 = 96

이 문제를 효율적으로 해결하기 위해서는 정확한 경로를 결정할 필요없이 위와 왼쪽의 셀을 방문한 횟수에 따라 각 셀을 방문한 횟수를 계산할 수 있습니다. 효과적으로 n여행을 한 번에 시뮬레이션 하고 각 셀이 몇 번 사용되는지 추적합니다.

johnchen902의 솔루션에서 영감을 얻은 푸시 기반 접근 방식으로 인한 실질적인 개선 :

r=lambda:map(int,raw_input().split())
h,w,n=r()
v=[n]+w*[0]
x=y=0
for i in range(h):
 for j,b in enumerate(r()):
    if i-x==j-y==0:d=v[j]&1^b;x+=d;y+=1^d
    f=v[j]+b>>1;v[j]-=f;v[j+1]+=f
print x,y

이전의 풀 기반 구현 :

r=lambda i:map(int,raw_input().split())
h,w,n=r(0)
x=range(h)
g=map(r,x)
v=[w*[0]for i in x]
v[0][0]=n-1
for i in x:
 for j in range(w):v[i][j]+=(i and(v[i-1][j]+(1^g[i-1][j]))/2)+(j and(v[i][j-1]+g[i][j-1])/2)
i=j=0
while i<h and j<w:f=g[i][j]^v[i][j]&1;j+=f;i+=1^f
print i,j

원래 언 골프 버전 :

h, w, n = map(int, raw_input().split())
grid = [map(int, raw_input().split()) for i in xrange(h)]

# Determine the number of times each cell was visited in the first n-1 trips
visits = [[0]*w for i in xrange(h)]
visits[0][0] = n-1
for i in xrange(h):
    for j in xrange(w):
        if i:
            # Count visits from above cell
            visits[i][j] += (visits[i-1][j] + (not grid[i-1][j])) // 2
        if j:
            # Count visits from left cell
            visits[i][j] += (visits[i][j-1] + grid[i][j-1]) // 2

# Flip the bits corresponding to each cell visited an odd number of times
for i in xrange(h):
    for j in xrange(w):
        grid[i][j] ^= visits[i][j] & 1

# Figure out where the final trip ends
i = j = 0
while i < h and j < w:
    if grid[i][j]:
        j += 1
    else:
        i += 1

print i, j

1
조건을 작성할 수있는 경우 not to 1^및 long 을 줄일 수 있습니다 f=g[i][j]^v[i][j]&1 j+=f i+=1^f.
Howard

@Howard : 감사합니다. 수정 사항이 적용되었습니다.
user2357112는 Monica

1
당신이 허용하는 경우 r매개 변수를 (데리고 r = lambda x: ...), 당신은 줄일 수 있습니다 g=[r()for i in x]g=map(r,x).
Roberto Bonvallet

@RobertoBonvallet : 예. 조언이 구현되었습니다.
user2357112는

8

루비, 159 143

n,*l=$<.read.split$/
i=->a{a.split.map &:to_i}
x=y=l.map!{|k|i[k]}
(n=i[n])[-1].times{x=y=0
(x+=f=l[x][y]^=1;y+=f^1)while x<n[0]&&y<n[1]}
p x,y

첫 번째 줄은 *연산자를 사용하여 한 변수에서 첫 번째 입력 줄을 잡고 다른 변수에서 나머지 입력을 가져옵니다. 다음 i함수는 변환을 정의 "1 2 3 4"[1, 2, 3, 4]모두 적용되며, l그리고 n. ( xy나중을 위해 저장됩니다.)

n[-1]의 마지막 요소 n이므로 다음 블록 (시뮬레이션)이 여러 번 실행됩니다. 첫째, xy(그들의 범위는 충분히 큰이 그래서 블록 외부에 선언) 0으로 초기화 된 후 시뮬레이션 라인은 실행 꽤 단정하지만, 여기에 몇 가지 논평 어쨌든입니다되는 :

l[x][y]<1?            is it zero (less than one)?
x+=l[x][y]=1          if it's zero, set it to one, and (conveniently) we can add that to x
:y+=(l[x][y]=0)+1     otherwise, set it to zero, add one, and add that to y
 while x<n[0]&&y<n[1] keep doing this while we're still inside the array

편집 : Howard가 제공하는 새로운 시뮬레이션 라인, 감사합니다! 나는 그것이 어떻게 작동하는지 이해한다고 확신하지만 설명을 추가 할 시간이 없으므로 나중에 추가 될 것입니다.

마지막으로 p x,y숫자를 출력하면 완료됩니다!


몇 가지 기본 승리 : 줄 바꿈을로 변경 $/하고 while 루프를로 줄일 수 있습니다 (x+=f=l[x][y]^=1;y+=f^1)while x<n[0]&&y<n[1]}.
Howard

4

델파이 XE3 (437 바이트 || 897 874 보너스 제외)

보너스로 이것을 해결하는 방법에 대해 생각할 때 나는 다음을 생각했습니다.
4 일 동안 걸 으면 0,0 셀이 4 번 변경됩니다. 오른쪽의 셀은 그 아래의 셀보다 두 배로 변경됩니다.
일수가 고르지 않고 셀의 숫자가 1로 시작하면 오른쪽의 셀이 아래의 셀보다 하나 이상을 가져오고 셀이 0 인 경우 다른 방법으로 주위를 가져옵니다.

모든 셀에 대해이 작업을 수행하면 다음과 같이 최종 값을 변경해야하는지 확인할 수 있습니다. 셀이 X 번 변경되었습니다. X mod 2> 0이면 셀을 변경하십시오.

다음 코드의 결과 :
{Whispers at JohnChen902} 지금 귀하의 찬성 투표를 받습니까? :피

uses SysUtils,Classes,idglobal;var a:TArray<TArray<byte>>;b:TArray<TArray<int64>>;h,w,x,y,t:int16;n:int64;s:string;r:TStringList;tra:byte;begin r:=TStringList.Create;readln(h,w,n);h:=h-1;w:=w-1;for y:=0to h do begin readln(s);r.Add(StringReplace(s,' ','',[rfReplaceAll]));end;SetLength(a,h);SetLength(b,h);for y:=0to h do begin SetLength(a[y],w);SetLength(b[y],w);for x:=1to Length(r[y])do a[y][x-1]:=Ord(r[y][x])-48;end;b[0][0]:=n-1;for Y:=0to h do for X:=0to w do begin t:=b[y][x];if x<w then b[y][x+1]:=b[y][x+1]+iif((t mod 2=1)and(a[y][x]=1),(t div 2)+1,t div 2);if y<h then b[y+1][x]:=b[y+1][x]+iif((b[y][x]mod 2=1)and(a[y][x]=0),(t div 2)+1,t div 2);end;for Y:=0to h do for X:=0to w do if b[y][x]mod 2=1then a[y][x]:=iif(a[y][x]=1,0,1);y:=0;x:=0;repeat a[y][x]:=iif(a[y][x]=1,0,1);if a[y][x]=1then inc(y) else inc(x);until(y>h)or(x>w);write(Format('%d %d',[y,x]));end.

언 골프

uses
  SysUtils,Classes,idglobal;
var
  a:TArray<TArray<byte>>;
  b:TArray<TArray<int64>>;
  h,w,x,y,t:int16;
  n:int64;
  s:string;
  r:TStringList;
  tra:byte;
begin
  r:=TStringList.Create;
  readln(h,w,n);
  h:=h-1;w:=w-1;
  for y:=0to h do
  begin
    readln(s);
    r.Add(StringReplace(s,' ','',[rfReplaceAll]));
  end;
  SetLength(a,h);
  SetLength(b,h);
  for y:=0to h do
  begin
    SetLength(a[y],w);
    SetLength(b[y],w);
    for x:=1to Length(r[y])do
      a[y][x-1]:=Ord(r[y][x])-48;
  end;
  b[0][0]:=n-1;
  for Y:=0to h do
    for X:=0to w do
    begin
      t:=b[y][x];
      if x<w then
        b[y][x+1]:=b[y][x+1]+iif((t mod 2=1)and(a[y][x]=1),(t div 2)+1,t div 2);
      if y<h then
        b[y+1][x]:=b[y+1][x]+iif((b[y][x]mod 2=1)and(a[y][x]=0),(t div 2)+1,t div 2);
    end;
  for Y:=0to h do
    for X:=0to w do
      if b[y][x]mod 2=1then
        a[y][x]:=iif(a[y][x]=1,0,1);
  y:=0;x:=0;
  repeat
    a[y][x]:=iif(a[y][x]=1,0,1);
    if a[y][x]=1then
      inc(y)
    else
      inc(x);
  until(y>h)or(x>w);
  write(Format('%d %d',[y,x]));
end.

아직 내 투표권을 얻지 못했습니다. 나는 저녁을 먹고 있었다. (Upvoted)
johnchen902

4

C ++ 213 바이트 * 0.5 = 106.5

여기 내 해결책이 있습니다. user2357112의 솔루션 과 유사 하지만 몇 가지 차이점이 있습니다.

  • 먼저 파견 하는 대신 위쪽 및 왼쪽에서 계산을의 오른쪽과 아래쪽에 배를 방문.
  • 둘째, 나는 모든 것을 (입력 읽기, 파견, 사람의 위치 추적) 동시에 수행합니다.
  • 셋째, 한 줄의 메모리 만 유지합니다.
#include <iostream>
int o[1001],h,w,r,c,i,j,t,u;int main(){std::cin>>h>>w>>*o;for(;i<h;i++)for(j=0;j<w;)std::cin>>t,u=o[j],o[j]/=2,u%2&&o[j+t]++,r-i|c-j||((u+t)%2?r:c)++,o[++j]+=u/2;std::cout<<r<<" "<<c<<"\n";}

ungolfed 버전은 다음과 같습니다.

#include <iostream>
using namespace std;
int o[1001];
int main(){
    int h, w, n;
    cin >> h >> w >> n;
    o[0] = n;
    int r = 0, c = 0;
    for(int i = 0; i < h; i++)
        for(int j = 0; j < w; j++){
            bool t;
            cin >> t;
            int u = o[j];
            o[j + 1] += u / 2;
            o[j] = u / 2;
            if(u % 2)
                (t ? o[j + 1] : o[j])++;
            if(r == i && c == j)
                ((u + t) % 2 ? r : c)++;
        }
    cout << r << " " << c << endl;
}

이 세 가지 차이점으로 인해 상황이 훨씬 더 심각해집니다. 인덱싱을 줄이고 여러 중복 데이터 구조를 결합 할 수 있습니다. 방문을 푸시하는 로직은 이전 셀에서 방문을 가져 오는 로직보다 훨씬 짧습니다. 수평 경계 조건은 데이터 구조를 오른쪽으로 추가 공간을 확장하여 간단히 처리되며 수직 경계 조건은 문제가되지 않습니다.
user2357112는 Monica

귀하의 답변을 상향 조정하고 개념을 내 코드에 통합했습니다. 지금까지 그들은 내 솔루션에서 84 바이트를 가져 와서 30 % 개선했습니다.
user2357112는 Monica

나는 당신을하지 않고 일부 바이트를 절약 할 수 있다고 생각 --*o;하고 대신에 남자를 아래로 움직이고 남자를 오른쪽으로 움직입니다.
user2357112는 Monica

@ user2357112 구현되었지만 이전 실수로 인해 코드 길이가 증가합니다 (218 바이트 여야 함).
johnchen902

3

파이썬, 177 바이트

Code Golfing에서 처음 시도한 것이므로 여기에 문제가 있으면 죄송합니다! user2357112의 코드를 기반으로 입력을 가져 오는 데 사용되는 코드입니다.

l=lambda:map(int,raw_input().split())
h,w,n=l()
m=[l() for i in[1]*h]
while n>0:
 n-=1;x=y=0
 while x!=w and y!=h:
  if m[y][x]>0:m[y][x]=0;x+=1
  else:m[y][x]=1;y+=1
print y,x

입력:

3 4 3
1 0 1 1
0 1 0 0
1 0 1 0

산출:

0 4

2

R, 196 바이트 * 0.5 = 98

f=function(h,w,n,x){I=J=rep(1,n);for(i in 1:h)for(j in 1:w){M=which(I==i&J==j);N=length(M);if(N){z=seq(1,N,by=2);if(x[i,j])z=-z;f=M[-z];s=M[z];I[f]=i;J[f]=j+1;I[s]=i+1;J[s]=j}};cat(I[n]-1,J[n]-1)}

언 골프 드 :

f=function(h,w,n,x) {
  I = J = rep(1,n)

  for(i in 1:h) for(j in 1:w) {
    M = which(I==i&J==j)
    N = length(M)
    if (N) {
      z = seq(1,N,by=2)
      if (x[i,j]) z = -z
      f = M[-z]
      s = M[z]
      I[f] = i
      J[f] = j+1
      I[s] = i+1
      J[s] = j
    }
  }
  cat(I[n]-1, J[n]-1)
}

용법:

f(3,4,4,matrix(c(1,0,1,0,1,0,1,0,1,1,0,0),3))
3 2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.