男がどこへ行くかを予測する


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数日後に男性の行き先を計算します。

入力:

最初の行では三つの整数であり、hwn

次のh行はw整数であり、男性の記録を示しています。

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

出力:

n数日後の男性の行き先を示す2つの整数。

サンプル入力:

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インデックスを使用します。それはどのように機能しますか?border + 1のようにすべきですか?2つ目は、スコアリングの2行目です。どういう意味ですか?
テウンプロンク14

4日目は3,2を正しく出力しますか?
テウンプロンク14

2
nコードが何であれ、1000000000日間すべての結果を計算し、その結果を出力する場合n、-50%のボーナスが得られますか?
user12205 14

@ace今、あなたはそのようにそれを置きます、それは理にかなっていますか?それをありがとう:P
Teun Pronk 14

@TeunPronkはい。それは私のせいです。
johnchen902

回答:



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 to 1^およびlong を短縮できますf=g[i][j]^v[i][j]&1 j+=f i+=1^f
ハワード14

@ハワード:ありがとう。編集が適用されました。
user2357112は

1
あなたが許可した場合r(パラメータを取るためにr = lambda x: ...)、あなたは短縮することができますg=[r()for i in x]g=map(r,x)
ロベルトボンバレット14

@RobertoBonvallet:うん。アドバイスを実施しました。
user2357112はMonicaをサポートします

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]、両方に適用されるln。(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

編集:ハワードが提供する新しいシミュレーションライン、ありがとう!私はそれがどのように機能するかを理解していると確信していますが、説明を追加する時間がないので、後で説明します。

最後にp x,y、数値を出力し、完了です!


いくつかの基本的な勝利:改行をに変更し$/、whileループをに減らすことができます(x+=f=l[x][y]^=1;y+=f^1)while x<n[0]&&y<n[1]}
ハワード14

4

Delphi XE3(437バイト|| ボーナスなしの897 874)

ボーナスでこれを解決する方法を考えるとき、私は次のことを考えました。
4日間歩くと、セル0,0は4回変更されます。右側のセルは、その下のセルと同じように2回変更されます。
日数が不均等で、セルの数が1から始まる場合、右側のセルは下のセルよりも1つ多くなり、セルが0の場合は逆になります。

すべてのセルに対してこれを行うことで、終了値を変更する必要があるかどうかを確認できます。セルはX回変更されました。X mod 2> 0の場合、セルを変更します。

結果は次のコード
になります。: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.

非ゴルフ

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のソリューションに似ていますが、いくつかの違いがあります。

  • まず、訪問時間を上と左から計算するのではなく、右と下にディスパッチします。
  • 第二に、私はすべてを同時に行います(入力の読み取り、ディスパッチ、男の位置の追跡)。
  • 第三に、私はメモリを1行だけ保持します。
#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;
}

これらの3つの違いは、物事をより簡潔にします。インデックス作成を短縮し、いくつかの冗長なデータ構造を組み合わせることができます。訪問を進めるロジックは、以前のセルから訪問をプルするロジックよりもはるかに短いことがわかりました。水平方向の境界条件は、データ構造を右側に余分なスペースを拡張するだけで処理され、垂直方向の境界条件は問題になりません。
user2357112は、Monicaを14

私はあなたの答えを支持し、自分のコードに概念を組み込みました。これまでのところ、彼らは私のソリューションから84バイトを取り出し、30%改善しました。
user2357112は、Monicaを14

を実行せずに、バイトを節約できる可能性があると思います。--*o;代わりに、どのケースで男を下に移動し、どのケースで男を右に移動します。
user2357112は、Monicaを14

@ user2357112実装されましたが、以前の間違いによりコード長が増加しました(218バイトであるはずです)。
johnchen902 14

3

Python、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.