남자가 어디로 갈지 예측


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. ( x및 y나중을 위해 저장됩니다.)

n[-1]의 마지막 요소 n이므로 다음 블록 (시뮬레이션)이 여러 번 실행됩니다. 첫째, x및 y(그들의 범위는 충분히 큰이 그래서 블록 외부에 선언) 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.