Teorema empat warna

13

The Four warna Teorema Negara yang tidak lebih dari empat warna yang diperlukan untuk mewarnai daerah peta.

Tantangan

Diberikan daftar batas Negara, berikan setiap ID negara bagian warna sehingga tidak ada dua negara bagian yang berdekatan memiliki warna yang sama. Outputnya harus berupa stylesheet CSS yang menetapkan warna ke kode ID 2 huruf negara. Berikut adalah peta SVG yang dapat diterapkan stylesheet. http://upload.wikimedia.org/wikipedia/commons/3/32/Blank_US_Map.svg

Aturan

  • Kode terpendek menang
  • daftar batas negara dapat digunakan
  • hanya 4 warna yang bisa digunakan.
  • daftar status dapat di-hardcode

Saran: Gunakan fill:properti CSS untuk mengubah warna, Misalnya#AL{fill:green}

Berikut adalah daftar batas negara

AL-FL
AL-GA
AL-MS
AL-TN
AR-LA
AR-MO
AR-MS
AR-OK
AR-TN
AR-TX
AZ-CA
AZ-CO
AZ-NM
AZ-NV
AZ-UT
CA-NV
CA-OR
CO-KS
CO-NE
CO-NM
CO-OK
CO-UT
CO-WY
CT-MA
CT-NY
CT-RI
DC-MD
DC-VA
DE-MD
DE-NJ
DE-PA
FL-GA
GA-NC
GA-SC
GA-TN
IA-MN
IA-MO
IA-NE
IA-SD
IA-WI
ID-MT
ID-NV
ID-OR
ID-UT
ID-WA
ID-WY
IL-IA
IL-IN
IL-KY
IL-MO
IL-WI
IN-KY
IN-MI
IN-OH
KS-MO
KS-NE
KS-OK
KY-MO
KY-OH
KY-TN
KY-VA
KY-WV
LA-MS
LA-TX
MA-NH
MA-NY
MA-RI
MA-VT
MD-PA
MD-VA
MD-WV
ME-NH
MI-OH
MI-WI
MN-ND
MN-SD
MN-WI
MO-NE
MO-OK
MO-TN
MS-TN
MT-ND
MT-SD
MT-WY
NC-SC
NC-TN
NC-VA
ND-SD
NE-SD
NE-WY
NH-VT
NJ-NY
NJ-PA
NM-OK
NM-TX
NM-UT
NV-OR
NV-UT
NY-PA
NY-VT
OH-PA
OH-WV
OK-TX
OR-WA
PA-WV
SD-WY
TN-VA
UT-WY
VA-WV
kyle k
sumber
Bisakah kita hardcode daftar perbatasan negara?
NinjaBearMonkey
@ hsl ya, tidak apa-apa untuk perbatasan negara hardcode.
kyle k
@steveverrill jika Anda dapat memikirkan metode yang lebih baik untuk mengubah warna yang akan lebih bagus. Saya menambahkan contoh yang menunjukkan cara menggunakan CSS.
kyle k
Tidakkah ini membutuhkan mereproduksi bukti Teorema Empat Warna itu sendiri? Karena Anda harus menangani setiap kasus yang mungkin?
barrycarter
1
Bukankah Teorema ini terbukti salah jika perbatasan negara bagian menyentuh lebih dari 3 negara bagian lainnya?
Pengoptimal

Jawaban:

4

Python, 320 karakter

import sys,random
S=[]
E={}
for x in sys.stdin:a=x[:2];b=x[3:5];S+=[a,b];E[a,b]=E[b,a]=1
C={0:0}
while any(1>C[s]for s in C):
 C={s:0for s in S};random.shuffle(S)
 for s in S:
    A=set([1,2,3,4])-set(C[y]for x,y in E if x==s)
    if A:C[s]=random.choice(list(A))
for s in C:print'#%s{fill:%s}'%(s,' bglrloieulmdede'[C[s]::4])

Menggunakan algoritma acak. Tetapkan warna ke status dalam urutan acak dengan memilih warna yang tidak bertentangan dengan status berdekatan yang telah diwarnai. Tampaknya bekerja dalam sepersepuluh detik atau lebih pada input yang diberikan.

Contoh output:

$ 4color.py < stategraph
#WA{fill:red}
#DE{fill:gold}
#DC{fill:blue}
#WI{fill:blue}
#WV{fill:red}
#FL{fill:lime}
#WY{fill:gold}
#NH{fill:red}
#NJ{fill:lime}
#NM{fill:gold}
#TX{fill:red}
#LA{fill:blue}
#NC{fill:blue}
#ND{fill:gold}
#NE{fill:blue}
#TN{fill:red}
#NY{fill:gold}
#PA{fill:blue}
#RI{fill:gold}
#NV{fill:red}
#VA{fill:gold}
#CO{fill:red}
#CA{fill:gold}
#AL{fill:blue}
#AR{fill:gold}
#VT{fill:lime}
#IL{fill:red}
#GA{fill:gold}
#IN{fill:lime}
#IA{fill:gold}
#OK{fill:blue}
#AZ{fill:lime}
#ID{fill:lime}
#CT{fill:red}
#ME{fill:blue}
#MD{fill:lime}
#MA{fill:blue}
#OH{fill:gold}
#UT{fill:blue}
#MO{fill:lime}
#MN{fill:red}
#MI{fill:red}
#KS{fill:gold}
#MT{fill:blue}
#MS{fill:lime}
#SC{fill:red}
#KY{fill:blue}
#OR{fill:blue}
#SD{fill:lime}

Contoh disisipkan ke svg .

Keith Randall
sumber
tanrupanya warna SVG yang didukung. Sayang sekali Anda hanya bisa mendapatkan satu tiga warna dengan ::4triknya.
Peter Taylor
1
@PeterTaylor: tan terlihat mengerikan. Benar-benar bernilai 1 karakter untuk menggunakan emas sebagai gantinya.
Keith Randall
Bisakah Anda menjamin algoritma ini akan selalu selesai dalam waktu yang terbatas asalkan ada solusi 4-warna? :)
barrycarter
@barrycarter: Namun dijamin akan selesai dengan probabilitas 1. Mungkin perlu waktu eksponensial dalam ukuran peta.
Keith Randall
@KeithRandall Saya agak menggoda, tapi ... jika Anda memeriksa pengulangan, bisa butuh 4 ^ (n-1) langkah untuk menemukan pewarnaan yang tepat (n-1 karena simetri warna). Jika Anda tidak memeriksa pengulangan, mungkin perlu waktu lebih lama. Saya baru saja menemukan solusinya tidak memuaskan, karena itu bukan "benar-benar" algoritma yang "tepat".
barrycarter
3

Prolog, 309 307 283 karakter

:-initialization m.
a-X:-assert(X);retract(X),1=0.
r:-maplist(get_char,[A,B,E,C,D,F]),(E=F;X=[A,B],Y=[C,D],a-X/Y,a-Y/X,(s/X;a-s/X),(s/Y;a-s/Y),r).
s+[]:- \+ (X*C,writef('#%s{fill:#%w}',[X,C]),1=0).
s+[X|T]:-member(C,[911,191,119,991]),a-X*C,\+ (X/Y,Y*C),s+T.
m:-r,bagof(X,s/X,L),s+L.

Algoritme menggunakan pencarian mundur / kedalaman-pertama untuk mengisi peta.

Sedikit lebih mudah dibaca:

:- initialization(main).

% Found on http://awarth.blogspot.de/2008/08/asserts-and-retracts-with-automatic.html
assert2(X) :- assert(X).
assert2(X) :- retract(X), fail.

% Reads all states into clauses "state-State",
% and all connections into "State-Neighbor" and "Neighbor-State".
read_states :-
    % Read a line "AB-CD\n"
    maplist(get_char, [A,B,E,C,D,F]),
    (   A = F;
        State = [A, B],
        Neighbor = [C, D],
        % Memorize the connection between State and Neighbor in both directions.
        assert(State/Neighbor),
        assert(Neighbor/State),
        % Memorize State and Neighbor for the list of states.
        (state/State; assert(state/State)),
        (state/Neighbor; assert(state/Neighbor)),
        % Continue for all lines.
        read_states
    ).

% Print out all colors.
solve([]) :-
    once((
        State*Color,
        writef('#%s{fill:%w}', [State, Color]),
        fail
    )); !.

% Use depth-first search to color the map.
solve([State|FurtherStates]) :-
    member(Color, ['#911', '#191', '#119', '#991']),
    assert2(State*Color),
    \+ (State/Neighbor, Neighbor*Color),
    solve(FurtherStates).

main :-
    read_states,
    bagof(State, state/State, States),
    solve(States).

Doa:

cat borders.txt | swipl -q ./fourcolors.pl

Hasil (baris baru tidak diperlukan):

#AL{fill:#911}#FL{fill:#191}#GA{fill:#119}#MS{fill:#191}#TN{fill:#991}#AR{fill:#911}#LA{fill:#119}#MO{fill:#191}#OK{fill:#119}#TX{fill:#191}#AZ{fill:#911}#CA{fill:#191}#CO{fill:#191}#NM{fill:#991}#NV{fill:#991}#UT{fill:#119}#OR{fill:#911}#KS{fill:#911}#NE{fill:#119}#WY{fill:#911}#CT{fill:#911}#MA{fill:#191}#NY{fill:#119}#RI{fill:#119}#DC{fill:#911}#MD{fill:#191}#VA{fill:#119}#DE{fill:#119}#NJ{fill:#191}#PA{fill:#911}#NC{fill:#911}#SC{fill:#191}#IA{fill:#911}#MN{fill:#191}#SD{fill:#991}#WI{fill:#119}#ID{fill:#191}#MT{fill:#119}#WA{fill:#119}#IL{fill:#991}#IN{fill:#191}#KY{fill:#911}#MI{fill:#911}#OH{fill:#119}#WV{fill:#991}#NH{fill:#911}#VT{fill:#991}#ME{fill:#191}#ND{fill:#911}

Disisipkan ke dalam SVG: http://jsbin.com/toniseqaqi/

kay kecewa pada SE
sumber
1

JavaScript (ES6) 269 279

Pencarian rekursif dengan backtracking. ~ 80 byte yang dihabiskan untuk parsing daftar negara.

 F=l=>{
   S=(a,b)=>S[a]=(S[a]||[]).concat(b),
   l.replace(/(..)-(..)/g,(_,a,b)=>S(a,b)+S(b,a)),
   k=Object.keys(S),
   R=(p,c=k[p])=>!c||['blue','gold','red','tan'].some(i=>!c.some(t=>S[t].c==i)&&(c.c=i,R(p+1)||(c.c='')),c=S[c]),
   R(0),
   k.map(k=>console.log('#'+k+'{fill:'+S[k].c+'}'))
 }

Tidak disatukan

F=l=>{
  var states = {}; // hash table with adiacent list for each state
  S=(a,b)=>states[a]=(states[a]||[]).concat(b);
  l.replace(/(..)-(..)/g,(_,a,b)=>S(a,b)+S(b,a)); // build the hash table from the param list 

  keys = Object.keys(states); // get the list of hashtable keys as an array (the 49 states id)
  Scan=(p)=> // Recursive scan function
  {
    var sId = keys[p]; // in sid the current state id, or undefined if passed last key
    if (!sId) return true; // end of keys, recursive search is finished 
    var sInfo = states[sId]; // in sInfo the aarray of adiacent states id + the color property

    return ['blue','gold','red','tan'].some( (color) => // check the four avaialabe colors
      {
        var colorInUse = sInfo.some( (t) => states[t].color == color); // true if an adiacent state already has the currnet color
        if (!colorInUse) // if the color is usable
        {
          sInfo.color = color; // assign the current color to the current state
          var ok = Scan(p+1); // proceed with the recursive scan on the next state
          if (!ok) // if recursive scan failed, backtrack
          {
            sInfo.color = ''; // remove the assigned color for the current state
          }
          return ok;
        }
      }
    )
  },
  Scan(0), // start scan 
  keys.forEach( (sId) => console.log('#'+sId+'{fill:'+states[sId].color+'}')) // output color list
}

Uji di konsol FireFox / FireBug

list = "AL-FL AL-GA AL-MS AL-TN AR-LA AR-MO AR-MS AR-OK AR-TN AR-TX AZ-CA AZ-CO AZ-NM "+
"AZ-NV AZ-UT CA-NV CA-OR CO-KS CO-NE CO-NM CO-OK CO-UT CO-WY CT-MA CT-NY CT-RI "+
"DC-MD DC-VA DE-MD DE-NJ DE-PA FL-GA GA-NC GA-SC GA-TN IA-MN IA-MO IA-NE IA-SD "+
"IA-WI ID-MT ID-NV ID-OR ID-UT ID-WA ID-WY IL-IA IL-IN IL-KY IL-MO IL-WI IN-KY "+
"IN-MI IN-OH KS-MO KS-NE KS-OK KY-MO KY-OH KY-TN KY-VA KY-WV LA-MS LA-TX MA-NH "+
"MA-NY MA-RI MA-VT MD-PA MD-VA MD-WV ME-NH MI-OH MI-WI MN-ND MN-SD MN-WI MO-NE "+
"MO-OK MO-TN MS-TN MT-ND MT-SD MT-WY NC-SC NC-TN NC-VA ND-SD NE-SD NE-WY NH-VT "+
"NJ-NY NJ-PA NM-OK NM-TX NM-UT NV-OR NV-UT NY-PA NY-VT OH-PA OH-WV OK-TX OR-WA "+
"PA-WV SD-WY TN-VA UT-WY VA-WV";
F(list);

Keluaran

#AL{fill:blue}
#FL{fill:gold}
#GA{fill:red}
#MS{fill:gold}
#TN{fill:tan}
#AR{fill:blue}
#LA{fill:red}
#MO{fill:gold}
#OK{fill:red}
#TX{fill:gold}
#AZ{fill:blue}
#CA{fill:gold}
#CO{fill:gold}
#NM{fill:tan}
#NV{fill:tan}
#UT{fill:red}
#OR{fill:blue}
#KS{fill:blue}
#NE{fill:red}
#WY{fill:blue}
#CT{fill:blue}
#MA{fill:gold}
#NY{fill:red}
#RI{fill:red}
#DC{fill:blue}
#MD{fill:gold}
#VA{fill:red}
#DE{fill:red}
#NJ{fill:gold}
#PA{fill:blue}
#NC{fill:blue}
#SC{fill:gold}
#IA{fill:blue}
#MN{fill:gold}
#SD{fill:tan}
#WI{fill:red}
#ID{fill:gold}
#MT{fill:red}
#WA{fill:red}
#IL{fill:tan}
#IN{fill:gold}
#KY{fill:blue}
#MI{fill:blue}
#OH{fill:red}
#WV{fill:tan}
#NH{fill:blue}
#VT{fill:tan}
#ME{fill:gold}
#ND{fill:blue}
edc65
sumber