Web tokilearning yang lama sudah tidak aktif, Anda sudah tidak bisa mengumpulkan jawaban untuk soal ini. Namun Anda masih dapat mempelajarinya di tulisan ini.
Oke kali ini saya akan membahas soal Webs dari tokilearning. Konon katanya soal ini digunakan untuk simulasi Pelatnas 2 TOKI 2010 di UGM. Dari gaya bahasanya, kelihatannya soal ini dibuat oleh Irvan Jahja. Sekilas, soal ini tampak menyeramkan. Pada kenyataannya tidak terlalu menyeramkan, asal kita memilah-milah dan tahu apa yang harus dikerjakan.
Tugas kita adalah menghitung berapa banyak segitiga yang ada!
Biasanya, soal geometri seperti ini erat hubungannya dengan graf. Hmm coba perhatikan, seandainya titik perpotongan dari dua benang kita anggap sebagai node, lalu benang yang menghubungkan antar dua titik perpotongan sebagai edge, maka kita dapatkan sebuah graf yang planar.
Berapa banyak node maksimumnya? Persoalan berapa banyaknya node ini serupa dengan persoalan berikut:
Diberikan sebuah kue berbentuk persegi. Dengan N kali pemotongan, berapa banyaknya potongan maksimum yang bisa dihasilkan?Jawab:
Misalkan sudah dilakukan X-1 kali pemotongan di kue tersebut dan banyaknya potongan yang dihasilkan sejauh ini adalah optimal (sebanyak mungkin). Jika kita memotong sekali lagi, kita pasti bisa memotong dengan melewati setiap garis potongan yang pernah dilakukan sebelumnya. Karena kita melewati X-1 bekas pemotongan, kita menghasilkan X buah potongan yang baru.
Dari observasi tersebut, kita dapat merancang rumus rekursif untuk jawaban atas pertanyaan di atas. Misalkan f(x) menyatakan banyaknya potongan kue maksimum jika dilakukan x kali pemotongan. Didapat:
f(0)=1, hanya ada 1 potong kue jika tidak dilakukan pemotongan sama sekali
f(x)=f(x−1)+x
Dalam bentuk bukan rekursif:
f(x)=1+1+2+3+...+x
atau
f(x)=1+x(x+1)2
Sehingga banyaknya node maksimalnya adalah O(N2)
Sekarang kita kembali lagi ke soal. Kapan 3 buah node (sebut saja u, v, dan w) menjadi sebuah segitiga sesuai yang diinginkan soal? Hal ini terjadi jika terdapat edge yang menghubungkan (u, v), (u, w), dan (v, w). Jadi kita tinggal pilih suatu node, lalu cek untuk setiap pasangan tetangganya apakah mereka terhubung. Jika ya, tambahkan jawaban akhir dengan 1. Di akhir, bagi jawaban dengan 3 karena satu segitiga akan dihitung 3 kali. Berhubung suatu titik tidak mungkin menjadi titik persekutuan dari 3 atau lebih garis, maka setiap node hanya akan memiliki maksimal 4 tetangga. Jadi jika grafnya sudah dibangun, menghitung banyaknya segitiga dapat dilakukan dalam O(N2)
Sekarang masalahnya tinggal bagaimana cara membangun graf tersebut. Pastinya anda membutuhkan cara untuk mencari titik potong sepasang segmen garis. Selain itu, anda juga mungkin membutuhkan cara untuk memeriksa apakah suatu titik berapa di suatu segmen garis. Segala yang dibutuhkan untuk menjawab pertanyaan tersebut adalah ilmu tentang vektor dalam geometri, terutama cross product. Saya tidak membahas bagaimana cara mencari titik potong antar segmen garis atau memeriksa titik ada di suatu garis. Anda harus mencari tahu sendiri.
Membangun graf dari masukan yang diberikan dapat dilakukan dalam O(N2), sehingga kompleksitas solusi adalah O(N2). Cukup untuk mendapatkan accepted. Berikut kode saya:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <string> #include <queue> #include <stack> #include <vector> #include <utility> #include <set> #define REP(a,b) for (int a=0; a<b; a++) #define FORU(a,b,c) for (int a=b; a<=c; a++) #define FORD(a,b,c) for (int a=b; a>=c; a--) #define RESET(a,b) memset(a, b, sizeof a) #define LOLO long long #define FI first #define SE second #define MP make_pair #define PB push_back #define PII pair<int,int> #define PDD pair<double,double> #define EPS 1e-8 #define __ puts("") #define x FI #define y SE #define xa FI.FI #define xb SE.FI #define ya FI.SE #define yb SE.SE using namespace std; vector< int > mmi[610],adlis[150000]; set<pii> him; PDD tik[150000]; pair<PII,PII> grs[610]; int n,m,h1,h2,h3,h4,tot; int a1,a2,b1,b2,p; LOLO da1,da2,db1,db2,dc1,dc2; PII konv( int a, int b){ int c,d; if ((a == 0) || (a == 2)){ c = b; } else if (a == 1){ c = m; } else { c = 0; } if ((a == 1) || (a == 3)){ d = b; } else if (a == 2){ d = m; } else { d = 0; } return MP(c,d); } int det(PII a, PII b, PII c){ da1 = a.x; da2 = a.y; db1 = b.x; db2 = b.y; dc1 = c.x; dc2 = c.y; LOLO h = (da1*db2) + (db1*dc2) + (dc1*da2) - (da1*dc2) - (db1*da2) - (dc1*db2); if (h < 0) return -1; if (h > 0) return 1; return 0; } bool insec(pair<PII,PII> a, pair<PII,PII> b){ h1 = det(a.FI, a.SE, b.FI); h2 = det(a.FI, a.SE, b.SE); h3 = det(b.FI, b.SE, a.FI); h4 = det(b.FI, b.SE, a.SE); if ((h1*h2 <= 0) && (h3*h4 <= 0) && !((h1==0) && (h2==0) && (h3==0) && (h4==0))){ return 1; } return 0; } double crosp( double a, double b, double c, double d){ return (a*d) - (b*c); } PDD getsec(pair<PII,PII> a, pair<PII,PII> b){ double h1,h2,le; double adx,ady; double bdx,bdy; bdx = b.xb - b.xa; bdy = b.yb - b.ya; le = sqrt (bdx*bdx + bdy*bdy); adx = a.xa - b.xa; ady = a.ya - b.ya; h1 = fabs (crosp(adx,ady,bdx,bdy)/le); adx = a.xb - b.xa; ady = a.yb - b.ya; h2 = h1 + fabs (crosp(adx,ady,bdx,bdy)/le); double px,py; px = a.xa + (h1/h2)*(a.xb - a.xa); py = a.ya + (h1/h2)*(a.yb - a.ya); return MP(px,py); } bool kom( int a, int b){ if ( fabs (tik[a].x - tik[b].x) > EPS){ return tik[a].x < tik[b].x; } else { return tik[a].y < tik[b].y; } } int main(){ scanf ( "%d%d" , &m, &n); REP(i,n){ scanf ( "%d%d%d%d" , &a1, &a2, &b1, &b2); grs[i].FI = konv(a1,a2); grs[i].SE = konv(b1,b2); } grs[n++] = MP(MP(0,0),MP(0,m)); grs[n++] = MP(MP(0,m),MP(m,m)); grs[n++] = MP(MP(m,m),MP(m,0)); grs[n++] = MP(MP(m,0),MP(0,0)); p=0; REP(i,n){ FORU(j,i+1,n-1){ if (insec(grs[i],grs[j])){ tik[p] = getsec(grs[i],grs[j]); mmi[i].PB(p); mmi[j].PB(p); p++; } } } REP(i,n){ sort(mmi[i].begin(), mmi[i].end(), kom); FORU(j,0,( int )mmi[i].size()-2){ adlis[mmi[i][j]].PB(mmi[i][j+1]); adlis[mmi[i][j+1]].PB(mmi[i][j]); him.insert(MP(mmi[i][j],mmi[i][j+1])); him.insert(MP(mmi[i][j+1],mmi[i][j])); } } tot=0; REP(i,p){ REP(j,adlis[i].size()){ FORU(k,j+1,( int )adlis[i].size()-1){ if (him.count(MP(adlis[i][j], adlis[i][k]))){ tot++; } } } } printf ( "%d\n" , tot/3); return 0; } |
Tidak ada komentar :
Posting Komentar