Уряд має обмежену кількість стін


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 Я дещо новачок у Code Golf. У моїй вимозі не вдалося вказати обмеження часу, тому такого не існує. На відповідь лежить тягар, щоб довести, що рішення є правильним для всіх випадків проблеми. Якщо у вас є рішення, яке вирішує деякі (але не всі) екземпляри розумним / крутим способом, я все-таки закликаю вас опублікувати це просто для розваги.
Rainbolt

2
Код гольфу зазвичай не вимагає обмежень у часі.
Hosch250

Класно! Ще одне запитання: чи потрібно вводити так, як ви вказали, чи можемо ми поставити його в іншій формі?
Клавдіу

@Claudiu Я не можу прийняти нічого, що не відповідає вимогам. Однак ви можете запропонувати змінити вимоги за допомогою кнопки редагування . Бачачи, що відповіді ще немає, я, ймовірно, відразу прийму редагування.
Rainbolt

Відповіді:


10

Математика, 257 253 символів

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

І o, xі sпозначаємо позиції "o", "x" і ". відповідно.

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

Тоді для будь-якої підмножини wз s(підмножин упорядковано відповідно до довжині), я видалити вершини в xі wз g( VertexDelete[g,x⋃w]), а також знайти довжину найкоротшого шляху від вершини «на нескінченності» до табору o. Якщо довжина нескінченна, тоді табір буде безпечним. Тож довжина першої такої wє мінімальною кількістю стін, необхідною для захисту огородження.

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

Приємно! Я подумав, що мене захоплять іншим підходом іншою мовою.
Клавдіу

1
Оновлення, але я би зробив це ще гордіше, якби ви пояснили свій код решті з нас.
Майкл Стерн

Чи може хтось підтвердити, що ця відповідь правильна, або надати в Інтернеті інтерпретатор для "Mathematica"? Не вдається знайти його.
Rainbolt

1
@Rusher Я перевірив це, і це твердо. Інтерпретатора в Інтернеті для ММ немає, але існує формат документа CDF, який можна завантажити, з яким я та ще декілька інших почали експериментувати, щоб поділитися рішеннями. Ви також можете безкоштовно придбати Mathematica за допомогою комп'ютера Raspberry Pi ARM, із застереженням, яке обмежено обчислювальною здатністю коробки. FWIW, ми, користувачі MM, робимо все можливе, щоб один одного бути чесними, і ми працюємо над тим, щоб зробити наші подання більш доступними (з проблемою також стикаються Matlab, Maple, мови MS, які не працюють на Mono тощо)
Джонатан Ван Матре

4

C, 827 799 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 (позначено, куди йдуть нові стіни @). Я сам спробував запустити ваш код, але , схоже,
Клавдіу

На жаль, здається, що гольф та алкоголь не дуже добре поєднуються ... Я граю в гольфі в якійсь невизначеній поведінці. Потрібно виправити зараз разом із 277 непотрібними символами.
Комінтерн

2
@Claudiu - Дивіться мій коментар вище, результати для опублікованої вами карти є на pastebin.com/r9fv7tC5 . Це завжди має дати найкоротшу відповідь, але я перевірив це лише з 10 або 15 карт, які, на мою думку, можуть бути кутовими справами. Мені буде цікаво дізнатись, чи може хтось ідентифікувати карти, для яких це не вдається.
Комінтерн

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виконує заливку і повертає справжнє значення, якщо потрапило в табір. Немає зайвих накладок, оскільки для правильного налаштування прокладки знадобилося занадто багато місця. D, з урахуванням набору стін для заповнення, дзвонить Cз кожної точки на краю таким чином, що Cприпадає на ці стіни, і друкується довжина і вихід, якщо жодна з них не дійшла до табору. Список стін також використовується для відстеження заливної заливки, тому копіювання дошки не потрібно! Trickily, Cтакож додає будь-які порожні місця , які він знаходить в список S, так що функція Dбуде також використовуватися для першої конструкції списку порожніх місць. З цієї причини я використовую sumзамість цього any, щоб забезпечити, що всі .s збираються на першому пробігу.

Я закликаю Dодин раз, потім копіюю список порожніх плям, Zоскільки Sвони будуть додаватися (неефективно, але дешевше за кількістю символів). Потім я використовую itertools.combinationsдля вибору кожного комбінації порожніх плям, від 0 плям вгору. Я запускаю кожне комбо, Dі він друкує довжину першого, який працює, створюючи виняток для виходу з програми. Якщо відповіді не знайдено, нічого не друкується.

Зауважте, що наразі програма не працює, якщо не потрібні стіни. Для цієї справи слід взяти +3 символи; не впевнений, чи потрібно.

Також зауважте, що це O(2^n)алгоритм, де nкількість порожніх плям. Отже, для повністю порожньої дошки розміром 15x15 з одним вкладишем посередині, це займе 2^(15*15-1)= 2.6959947e+67ітерації для завершення, що дійсно буде дуже довгим!


1

Грувий: 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

Діалог 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, oна 1, .на 2, а всі інші на 3

s←(4,4,⍨⍉)⍣2 функція, яка оточує матрицю з 4s

a← присвоїти змінній числову матрицю, оточену 4s a

b←⍸2= b- це список пар координат, де знаходяться 2s (тобто .-s)

(,⍳2⊣¨b)/¨⊂b генерують всі комбінації елементів b

c[⍋≢¨c←...] сортуйте їх за розміром

{... :⍬⋄≢⍵}¨ для кожної комбінації перевірте щось і поверніть його довжину або порожній список

⊃∊ перший не порожній результат

d←0@⍵⊢a dє aз деякими елементами, заміненими на 0

4= створити булеву матрицю - де чотири? тобто кордон, який ми додали

{...}⍣≡ продовжуйте застосовувати функцію, {}поки результат не стабілізується

3∨/3∨⌿⍵ "булева або" кожен елемент зі своїми сусідами

s результат буде меншим, тому давайте знову створимо кордон

(×d)∧ застосуйте ненульові елементи d(не стінки) як булева маска

a[⍸× ...] що aвідповідає 1s в нашій булевій матриці?

1∊ чи є 1s, тобто oтабори?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.