ทำนายตำแหน่งที่ผู้ชายจะไป


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, และwn

ใน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%
    • อย่าเพียงคำนวณผลลัพธ์ทั้งหมด 1000000000 วันหรือทำสิ่งที่คล้ายคลึงกันอย่างโง่เพื่อรับโบนัสนี้ ค้นหาอัลกอริทึมที่มีประสิทธิภาพ!

2 สิ่งที่ฉันไม่เข้าใจ ผลลัพธ์บางครั้งคุณใช้ดัชนี 0 ครั้งอื่น ๆ ที่คุณไม่ มันทำงานอย่างไร มันควรจะเป็นเหมือน +1 + ชายแดน? สิ่งที่สองคือบรรทัดที่สองที่มีการให้คะแนน คุณหมายความว่าอย่างไร
Teun Pronk

วันที่ 4 ควรให้ผลลัพธ์ที่ 3,2 ใช่ไหม
Teun Pronk

2
หากไม่ว่าอะไรnรหัสของฉันจะคำนวณผลลัพธ์ทั้งหมด 1000000000 วันจากนั้นแสดงผลลัพธ์nฉันจะยังได้รับโบนัส -50% อีกหรือไม่
user12205

@ ตอนนี้คุณใส่มันแบบนั้นมันทำให้รู้สึกใช่ไหม? ขอบคุณสำหรับสิ่งนั้น: 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

Python 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 ไปและยาวถ้าเงื่อนไขสามารถเขียนได้1^ f=g[i][j]^v[i][j]&1 j+=f i+=1^f
Howard

@ วิธี: ขอบคุณ นำการแก้ไขมาใช้
user2357112 รองรับโมนิก้า

1
หากคุณอนุญาตให้rใช้พารามิเตอร์ ( r = lambda x: ...) คุณสามารถย่อg=[r()for i in x]ให้สั้นลงg=map(r,x)ได้
Roberto Bonvallet

@RobertoBonvallet: Yup ดำเนินการตามคำแนะนำแล้ว
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ถูกกำหนดค่าเริ่มต้นเป็นศูนย์ (พวกเขาถูกประกาศนอกบล็อกเพื่อให้ขอบเขตมีขนาดใหญ่พอ) จากนั้นสายการจำลองจะถูกดำเนินการซึ่งเป็นการอธิบายตนเองค่อนข้างสวย แต่นี่เป็นคำอธิบายบางส่วน:

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เอาท์พุทตัวเลขและเราเสร็จแล้ว!


บางชนะพื้นฐานเปลี่ยนไปขึ้นบรรทัดใหม่และห่วงในขณะที่สามารถลดลงได้$/ (x+=f=l[x][y]^=1;y+=f^1)while x<n[0]&&y<n[1]}
Howard

4

Delphi XE3 (437 bytes || 897 874 โดยไม่นับโบนัส)

เมื่อคิดถึงวิธีแก้ปัญหานี้ด้วยโบนัสฉันคิดถึงสิ่งต่อไปนี้
ถ้าคุณเดิน 4 วันเซลล์ 0,0 จะเปลี่ยน 4 ครั้ง เซลล์ทางด้านขวาจะถูกเปลี่ยนสองครั้งเช่นเดียวกับเซลล์ที่อยู่ด้านล่าง
หากมีจำนวนวันไม่สม่ำเสมอและจำนวนในเซลล์เริ่มต้นด้วย 1 เซลล์ทางด้านขวาจะได้รับมากกว่าเซลล์ที่อยู่ด้านล่างและอีกทางหนึ่งหากเซลล์เป็น 0

ด้วยการทำเช่นนี้กับทุกเซลล์คุณสามารถดูว่าควรเปลี่ยนค่าสิ้นสุดหรือไม่โดย: เซลล์เปลี่ยนเป็น X คูณ ถ้า X mod 2> 0 ให้เปลี่ยนเซลล์

ผลลัพธ์ในรหัสต่อไปนี้:
{Whispers at JohnChen902} ฉันจะได้รับ upvote ของคุณตอนนี้หรือไม่ : P

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.

Ungolfed

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.

คุณยังไม่ได้รับคะแนนของฉัน ฉันกินข้าวเย็น (
โหวตขึ้น

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";}

นี่คือรุ่นที่ไม่ได้แต่งแต้ม:

#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

Python ขนาด 177 ไบต์

ความพยายามครั้งแรกของฉันในการเล่นกอล์ฟรหัสดังนั้นขออภัยถ้าฉันมีอะไรผิดปกติที่นี่! รหัสที่ใช้เพื่อรับอินพุตตามรหัสของ 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)}

Ungolfed:

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.