政府墙壁供应有限


28

介绍

知识渊博的高尔夫球手为我们准备了世界末日的洪水。撤离有危险的地区,人口转移到高地。

我们低估了洪水(或者@ user12345的代码中存在错误)。一些高地地区正在迅速接近海平面。必须竖起墙壁,以确保现在人口稠密的营地的生存。可悲的是,政府的隔离墙供应有限。

问题

我们的世界末日场景由一行中的两个数字n和来描述m。在该行之后是每行n具有m值的行,仅用一个空格分隔。每个值将是四个字符之一。

  • x不可逾越。水不能在这里流动。不能在这里筑墙。
  • -不稳定 水可以在这里流过。不能在这里筑墙。
  • .稳定。水可以流过这里。可以在这里竖起墙壁。
  • o营地。水可以流过这里。如果是这样,每个人都会死亡。在这里不能建墙。

水将从地图的所有边缘流出,除非该边缘无法通行或在瓷砖上建了墙。编写一个程序,该程序可以输出保护营地所需的最小墙数。

输入示例

 6 7
 x . . x x x x
 x . . x - - x
 x . x x - - x
 x . o o o - .
 x . o o o - .
 x x x x x x x

示例输出

3

假设条件

  • 水只正交流动
  • 每种情况下,营地仅以一个对角连续的块存在
  • 解决方案将始终存在(尽管可能需要大量的墙壁)
  • 营地不能位于边缘,因为场景将无法解决
  • 2 n<<16
  • 2 m<<16
  • 输入可以从stdin提供,可以从“ city.txt”中读取,也可以作为单个参数接受

最短的代码胜出!


2
程序正确是可以接受的,但是花费比已知的宇宙更长的时间才能为某些问题实例提供解决方案吗?
Claudiu 2014年

@Claudiu我是Code Golf的新手。我的要求未能指定时间限制,因此不存在时间限制。负担落在答案上,以证明解决方案适用于所有问题实例。如果您有一个解决方案可以巧妙/巧妙地解决一些(但不是全部)实例,我仍然鼓励您发布它只是为了好玩。
雨螺栓

2
打码高尔夫通常不需要时间限制。
Hosch250 2014年

凉!另一个问:是否要求您输入的内容与您指定的相同,或者我们可以将其转换为其他形式?
Claudiu 2014年

@Claudiu我不能接受超出要求的任何内容。但是,您可以使用“ 编辑”按钮建议对需求进行编辑。既然还没有答案,我可能会马上接受修改。
雨螺栓

Answers:


10

Mathematica,257253个字符

d="city.txt"~Import~"Table";g=EdgeAdd[#,∞<->Tr@#&/@Position[VertexDegree@#,2|3]]&@GridGraph@d[[1,{2,1}]];{o,x,s}=Tr/@Position[Join@@d[[2;;]],#]&/@{"o","x","."};Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]

输入是从读取的"city.txt"

说明:

Mathematica具有许多处理图形的功能。

首先,我从中读取数据"city.txt"

d="city.txt"~Import~"Table";

然后我构造一个网格图带有'm'*'n'个顶点(GridGraph@d[[1,{2,1}]]),并向其中添加一个“无穷顶点”,该顶点与图的“边缘”上的每个顶点相连。这个顶点是水从那里流出的。

g=EdgeAdd[#,∞<->Tr@#&/@Position[VertexDegree@#,2|3]]&@GridGraph@d[[1,{2,1}]];

而且oxs表示“ o”,“ x”和“”的位置。分别。

{o,x,s}=Tr/@Position[Join@@d[[2;;]],#]&/@{"o","x","."};

那么对于任意子集ws(子集是按长度排序),我删除的顶点xw来自gVertexDelete[g,x⋃w]),并从“在无穷远处顶点”的营地找到最短路径的长度o。如果长度是无穷大,则该营地将是安全的。因此,第一个这样的长度w是保护营地所需的最小墙数。

Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]

真好!我想我会被另一种语言的另一种方法掩盖。
Claudiu 2014年

1
致谢,但如果您能为我们其他人解释您的代码,我将为此而自豪。
迈克尔·斯特恩

有人可以保证这个答案是正确的,还是可以为“ Mathematica”提供在线解释器?找不到一个。
Rainbolt 2014年

1
@Rusher我已经验证了,它很可靠。没有针对MM的在线解释器,但是有一个可下载的CDF文档格式,我和其他几个人已经开始尝试以共享解决方案。您还可以通过Raspberry Pi ARM计算机免费获得Mathematica,但需要注意的是,盒子的计算能力有限。FWIW,我们的MM用户竭力保持彼此的诚实,我们正在努力使我们的提交内容更易于访问(Matlab,Maple,在Mono上不起作用的MS语言也面临此问题)
Jonathan Van Matre 2014年

4

C,827799 522

打高尔夫球:

#define N for(
#define F(W,X,Y,Z) N i= W;i X Y;i Z)
#define C(A,B,C) if(c[A][B]==C)
#define S(W,X,Y,Z,A,B) p=1;F(W,X,Y,Z)C(A,B,120)p=0;if(p){F(W,X,Y,Z){C(A,B,46){c[A][B]='x';z++;Q();break;}}}else{F(W,X,Y,Z){C(A,B,120)break;else c[A][B]='o';}}
p,m,z,w,h,o,i,u,l,x,y;char c[16][16];Q(){N u=0;u<h;u++)N l=0;l<w;l++)if(c[u][l]=='o'){x=u;y=l;S(x,>,m,--,i,y)S(y,>,m,--,x,i)S(y,<,w,++,x,i)S(x,<,h,++,i,y)}}main(int a, char **v){h=atoi(v[1]);w=atoi(v[2]);N m=-1;o<h;o++)N i=0;i<w;i++)scanf("%c",&c[o][i]);Q();printf("%d",z);}

输入是通过高度和命令行参数来指定的,然后像这样在stdin上将网格作为单个字符串读取:./a.out 6 7 < input其中输入是这种形式(从左到右,从上到下):

x..xxxxx..x--xx.xx--xx.ooo-.x.ooo-.xxxxxxx

“可读”:

#define F(W,X,Y,Z) for(i= W;i X Y;i Z)
#define C(A,B,C) if(c[A][B]==C)
#define S(W,X,Y,Z,A,B) p=1;F(W,X,Y,Z)C(A,B,120)p=0;if(p){F(W,X,Y,Z){C(A,B,46){c[A][B]='x';z++;Q();break;}}}else{F(W,X,Y,Z){C(A,B,120)break;else c[A][B]='o';}}

/*Example of an expanded "S" macro:
p=1;
for(i=x;i>m;i--) if(c[i][y]==120) p=0;
if(p)
{
    for(i=x;i>m;i--)
    {
        if(c[i][y]==46)
        {
            c[i][y]='x';
            z++;
            Q();
            break;
        }
    }
}
else
{
    for(i= x;i > m;i --)
    {
        if(c[i][y]==120) break;
        else c[i][y]='o';
    }
}
*/

p,m,z,w,h,o,i,u,l,x,y;
char c[16][16];
Q(){
    for(u=0;u<h;u++)
        for(l=0;l<w;l++)
            if(c[u][l]=='o')
            {
        x=u;y=l;
        S(x,>,m,--,i,y)
        S(y,>,m,--,x,i)
        S(y,<,w,++,x,i)
        S(x,<,h,++,i,y)
            }
}

main(int a, char **v)
{
    h=atoi(v[1]);
    w=atoi(v[2]);
    for(m=-1;o<h;o++)
        for(i=0;i<w;i++)
            scanf("%c",&c[o][i]);
    P();
    Q();
    printf("%d\n",z);
    P();
}

//Omitted in golfed version, prints the map.
P()
{
    for(o=0;o<h;o++)
    {
        for (i=0;i<w;i++) printf("%c",c[o][i]);
        printf("\n");
    }   
}

距离@Claudiu的解决方案还差得很远,但是它运行得非常快。它不是从边缘填充洪水,而是找到营地并从“ o”标记向外工作。

  • 如果在营地旁边遇到任何不稳定的地面,它将在其上扩大营地。
  • 如果网格上的任何营地在每个方向上都没有至少一堵墙,它会沿该方向移动,直到可以建造一堵墙为止。
  • 放置每个新的墙部分后,将重复查找下一个要放置的墙部分。

样品墙放置:

x..xxxx                           x..xxxx
x..x--x                           x..xoox
x.xx--x                           x3xxoox
x.ooo-.  <-- results in this -->  xooooo1
x.ooo-.                           xooooo2
xxxxxxx                           xxxxxxx

呵呵有趣的方法!它总是给出最短的答案吗?例如,它给这张地图什么答案?它应该是3(标记有新墙@)。我尝试自己运行您的代码,但是似乎没有用
Claudiu 2014年

糟糕,打高尔夫球和酗酒似乎并不能很好地融合在一起。。。我打了一些不确定的动作。现在应该与277个不必要的字符一起修复。
Comintern 2014年

2
@Claudiu-请参阅我的评论,您发布的地图的结果位于pastebin.com/r9fv7tC5。这应该总是给出最短的答案,但是我只用10或15张地图进行了测试,我认为这可能会带来一些极端情况。我很想知道是否有人可以识别失败的地图。
Comintern

4

Python中,553 525 512 449 414 404 387 368字符(4吗?调用)

我打高尔夫球太开心了。如果您尝试压缩它,则要大82个字节!现在,这是一种紧凑性和缺乏重复性的度量。

R=range;import itertools as I
f=map(str.split,open('city.txt'))[1:]
S=[]
def D(q):
 q=set(q)
 def C(*a):
    r,c=a
    try:p=(f[r][c],'x')[a in q]
    except:p='x'
    q.add(a)
    if'.'==p:S[:0]=[a]
    return p<'/'and C(r+1,c)|C(r-1,c)|C(r,c+1)|C(r,c-1)or'o'==p
 if sum(C(j,0)|C(j,-1)|C(0,j)|C(-1,j)for j in R(16))<1:print n;B
D(S);Z=S[:]
for n in R(len(Z)):map(D,I.combinations(Z,n))

缩进级别是空格,制表符。

用法

从读取city.txt

6 7
x . . x x x x
x . . x - - x
x . x x - - x
x . o o o - .
x . o o o - .
x x x x x x x

调用如下:

$ python floodfill_golf.py 2>X
3

2>X是通过引发异常隐藏,因为程序退出标准错误。如果认为这不公平,请随意添加4个字符进行调用。

说明

简单的蛮力。C进行洪水填充,如果撞到营地,则返回true。没有多余的填充,因为它花费了太多的空间来正确设置填充。D给定一组要填充的墙,请C从边缘上的每个点调用,C以说明这些墙,并打印长度并在没有人到达营地时退出。墙壁列表也可用于跟踪洪水填充,因此无需复制木板!特殊重,C还追加发现到列表中的任意空白区域,S的,所以功能D用于第一构建空点的名单。因此,我使用sum代替any来确保所有.在第一次运行时收集。

我调用D一次,然后将空点列表复制进去,Z因为S它将一直被追加(效率低,但字符数便宜)。然后,我使用itertools.combinations从0个点开始选择每个空点组合。我通过每个组合D,它打印出第一个有效的的长度,引发退出程序的异常。如果未找到答案,则不会打印任何内容。

请注意,当前,如果不需要墙,该程序将无法运行。照顾到这种情况将是+3个字符;不知道是否有必要。

另请注意,这是一种O(2^n)算法,其中n是空白点的数量。因此,对于一块15x15的完全空的木板,中间有一个营地,这将需要2^(15*15-1)= 2.6959947e+67次迭代才能完成,这确实将是很长的时间!


1

Groovy的:841 805 754

i=new File("city.txt").getText()
x=i[2] as int
y=i[0] as int
m=i[4..i.length()-1].replaceAll('\n','').toList()
print r(m,0)
def r(m,n){if(f(m))return n;c=2e9;g(m).each{p=r(it,n+1);if(p<c)c=p;};return c;}
def f(m){u=[];u.addAll(m);for(i in 0..(x*y)){for(l in 0..m.size()-1){n(l,u);s(l,u);e(l,u);w(l,u);}};m.count('o')==u.count('o')}
def n(i,m){q=i-x;if((((q>=0)&(m[q]=='!'))|(q<0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def s(i,m){q=i+x;if((((q>=0)&(m[q]=='!'))|(q<0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def e(i,m){q=i+1;if((((q%x!=0)&(m[q]=='!'))|(q%x==0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def w(i,m){q=i-1;if((((i%x!=0)&(m[q]=='!'))|(i%x==0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def g(m){v=[];m.eachWithIndex{t,i->if(t=='.'){n=[];n.addAll(m);n[i]='W';v<<n}};return v}

取消高尔夫:

def i = new File("city.txt").getText()
x=i[2].toInteger()
y=i[0].toInteger()
def m=i[4..i.length()-1].replaceAll('\n','').toList()
println r(m, 0)

def r(m, n){
    if(f(m)) return n
    def c = Integer.MAX_VALUE

    getAllMoves(m).each{ it -> 
        def r = r(it, n+1)
        if(r < c) c = r
    }
    return c;
}

def f(m){
    def t = []
    t.addAll(m)
    for(i in 0..(x*y)){
        for(l in 0..m.size()-1){
            n(l,t);s(l,t);e(l,t);w(l,t);
        }
    }
    m.count('o')==t.count('o')
}

def n(i,m){
    def t = i-x;
    if( ( ( (t >= 0) && (m[t]=='!') ) || (t < 0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def s(i,m){
    def t = i+x;
    if( ( ( (t >= 0) && (m[t]=='!') ) || (t < 0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def e(i,m){
    def t = i+1;
    if( ( ( (t%x!=0) && (m[t]=='!') ) || (t%x==0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    } 
}

def w(i,m){
    def t = i-1;
    if( ( ( (i%x!=0) && (m[t]=='!') ) || (i%x==0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def getAllMoves(m){
    def moves = []
    m.eachWithIndex { t, i ->
        if(t=='.'){
            def newList = []
            newList.addAll(m)
            newList[i]='W'
            moves << newList
        }
    }
    return moves
}

还有更多的高尔夫运动...

如果没有解决方案,则返回2E9。


0

Dyalog APL,91 字节

⊃∊{1∊a[⍸×{(×d)∧s 3∨/3∨⌿⍵}⍣≡4=d←0@⍵⊢a]:⍬⋄≢⍵}¨c[⍋≢¨c←(,⍳2⊣¨b)/¨⊂b←⍸2=a←(s←(4,4,⍨⍉)⍣2)'xo.'⍳⎕]

假设⎕IO=0使用v16.0(@)中的功能,则运行时间与.-s 的数量成指数关系

被评估的输入,必须是字符矩阵

'xo.'⍳ 替换x为0,替换为o1,.替换为2,所有其他替换为3

s←(4,4,⍨⍉)⍣2 用4s包围矩阵的函数

a← 将用4s包围的数字矩阵分配给变量 a

b←⍸2= b是2(即.-s)所在的坐标对的列表

(,⍳2⊣¨b)/¨⊂b 生成的元素的所有组合 b

c[⍋≢¨c←...] 按大小排序

{... :⍬⋄≢⍵}¨ 对于每种组合,请检查某项并返回其长度或空列表

⊃∊ 第一个非空结果

d←0@⍵⊢a da某些元素替换为0

4= 创建布尔矩阵-4s在哪里?即我们添加的边框

{...}⍣≡ 继续应用功能{}直到结果稳定

3∨/3∨⌿⍵ “布尔或”每个元素及其相邻元素

s 结果将更小,所以让我们重新创建边框

(×d)∧d(非墙)的非零元素用作布尔蒙版

a[⍸× ...] 什么a对应于我们的布尔矩阵的1秒?

1∊ 有1个,即o露营吗?

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.