预测男人会去哪里


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几天。

样本输入:

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索引。这是如何运作的?应该像border + 1吗?第二件事是得分的第二行。那是什么意思
Teun Pronk

第4天应该输出3,2对吗?
Teun Pronk

2
如果不管是什么n,我的代码都会计算所有1000000000天的结果,然后输出的结果n,我是否还会获得-50%的奖励?
user12205 2014年

@ace现在您这样说,这确实有意义吗?谢谢你:P
Teun Pronk

@TeunPronk是的。我的错。
johnchen902

Answers:


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
请不要要求解释;-)在不破坏和调试这种野兽的情况下,我什至无法更改它。
霍华德

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
霍华德

@霍华德:谢谢。应用了修改。
user2357112支持Monica 2014年

1
如果允许r使用参数(r = lambda x: ...),则可以缩短g=[r()for i in x]g=map(r,x)
罗伯托·邦瓦莱特

@RobertoBonvallet:是的。实施建议。
user2357112支持Monica 2014年

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。(xy保存以备后用。)

n[-1]是的最后一个元素n,因此以下代码块(模拟)执行了多次。首先,xy初始化为零(声明它们的块,使它们的范围足够大之外),然后模拟线被执行,这是不言自明,但这里的一些评论反正:

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]}
2014年

4

Delphi XE3(437字节|| 897 874(不包括奖金)

在考虑如何使用奖金解决此问题时,我想到了以下几点。
如果您步行4天,则将0,0更改为4次。右侧的单元格的变化是其下方单元格的两倍。
如果天数不均匀,并且单元格中的数字以1开头,则右侧的单元格比下方的单元格多一个,如果单元格为0,则反之。

通过对每个单元格执行此操作,您可以查看是否应通过以下方式更改最终值:单元格已更改X次。如果X mod 2> 0,则更改单元格。

结果如下:
{JohnChen902的窃窃私语}我现在得到您的支持吗?: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.

你还没有得到我的投票。我在吃晚饭。(已投票)
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";}

这是非高尔夫版本:

#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 2014年

我赞成您的回答,并将这些概念合并到我自己的代码中。到目前为止,他们已经从我的解决方案中取出了84个字节,提高了30%。
user2357112支持Monica 2014年

我怀疑您可以通过不执行操作来节省一些字节--*o;,而是切换哪种情况下将男生下移和哪种情况下将男生向右移。
user2357112支持Monica 2014年

@ user2357112已实现,但由于先前的错误(本应为218个字节)而导致代码长度增加。
johnchen902'4

3

Python,177字节

我第一次尝试Code Codeing,如果在这里遇到问题,对不起!用于根据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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.