|
@@ -2,7 +2,6 @@ package main
|
2
|
2
|
|
3
|
3
|
import (
|
4
|
4
|
"fmt"
|
5
|
|
- "math/rand"
|
6
|
5
|
"os"
|
7
|
6
|
"sort"
|
8
|
7
|
)
|
|
@@ -66,7 +65,6 @@ func (rs ByEndtime) Less(i, j int) bool {
|
66
|
65
|
|
67
|
66
|
type Scheduler interface {
|
68
|
67
|
Add(*Car)
|
69
|
|
- RemoveAtIndex(k int) *Car
|
70
|
68
|
Pop() *Car
|
71
|
69
|
}
|
72
|
70
|
|
|
@@ -78,8 +76,7 @@ type Car struct {
|
78
|
76
|
X int
|
79
|
77
|
Y int
|
80
|
78
|
|
81
|
|
- score int
|
82
|
|
- pqindex int // used for removal in prority queue
|
|
79
|
+ score int
|
83
|
80
|
}
|
84
|
81
|
|
85
|
82
|
func (c *Car) Update(r *Ride) {
|
|
@@ -135,89 +132,74 @@ func max(a, b int) int {
|
135
|
132
|
}
|
136
|
133
|
}
|
137
|
134
|
|
138
|
|
-var bestTotalScore int
|
139
|
|
-
|
140
|
|
-// invariant : when entering and leaving function,
|
141
|
|
-// Sched has the "same" heap. Same means successive
|
142
|
|
-// popped values will be the same (but the internal
|
143
|
|
-// ordering of nodes may be different)
|
144
|
|
-func Choose(cumulativeScore int, depth int) {
|
145
|
|
- if cumulativeScore > bestTotalScore {
|
146
|
|
- bestTotalScore = cumulativeScore
|
147
|
|
- }
|
148
|
|
- c := Sched.Pop()
|
149
|
|
- if c == nil {
|
150
|
|
- // Stop recursion, empty car list,
|
151
|
|
- // could not match cars to rides
|
152
|
|
- return
|
153
|
|
- }
|
|
135
|
+func (c *Car) CanPick(r *Ride) bool {
|
|
136
|
+ return !r.used && r.f >= c.EarliestFinish(r)
|
|
137
|
+}
|
154
|
138
|
|
155
|
|
- var bestRides []struct {
|
156
|
|
- r *Ride
|
157
|
|
- lenOfRide int
|
158
|
|
- total int
|
159
|
|
- }
|
160
|
|
- // fmt.Printf("car %d\n", c.ID)
|
|
139
|
+func (c *Car) pickClosestLate() *Ride {
|
|
140
|
+ var best *Ride
|
|
141
|
+ var dbest = 999999999
|
161
|
142
|
for _, r := range Rides {
|
162
|
|
- if r.used {
|
|
143
|
+ if !c.CanPick(r) {
|
163
|
144
|
continue
|
164
|
145
|
}
|
165
|
|
- if r.Length() > 6000 {
|
166
|
|
- continue
|
|
146
|
+ d := c.distanceTo(r.a, r.b)
|
|
147
|
+ if d < dbest && d > r.s-c.Arrival {
|
|
148
|
+ best = r
|
|
149
|
+ dbest = d
|
167
|
150
|
}
|
168
|
|
- if r.f < c.EarliestFinish(r) {
|
|
151
|
+ }
|
|
152
|
+ return best
|
|
153
|
+}
|
|
154
|
+
|
|
155
|
+func Choose(c *Car) *Ride {
|
|
156
|
+ var bestRide *Ride
|
|
157
|
+ bestLenOfRide := 0
|
|
158
|
+ bestTotal := 0
|
|
159
|
+ // fmt.Printf("car %d\n", c.ID)
|
|
160
|
+ for _, r := range Rides {
|
|
161
|
+ if !c.CanPick(r) {
|
169
|
162
|
continue
|
170
|
163
|
}
|
171
|
164
|
// fmt.Printf("%d %d -> %d %d\n", r.a, r.b, r.x, r.y)
|
172
|
165
|
lenOfRide := r.length()
|
173
|
166
|
total := max(c.distanceTo(r.a, r.b), r.s-c.Arrival) + lenOfRide
|
174
|
167
|
// fmt.Printf("%d/%d\n", lenOfRide, total)
|
175
|
|
- if len(bestRides) == 0 || lenOfRide*bestRides[len(bestRides)-1].total > total*bestRides[len(bestRides)-1].lenOfRide {
|
176
|
|
- bestRides = append(bestRides, struct {
|
177
|
|
- r *Ride
|
178
|
|
- lenOfRide int
|
179
|
|
- total int
|
180
|
|
- }{r, lenOfRide, total})
|
181
|
|
- // shitty sort-of-correct-but-quite-incorrect way
|
182
|
|
- // of picking next best n rides
|
183
|
|
- n := 1
|
184
|
|
- if rand.Intn(max(1, int(N/5))) == 0 {
|
185
|
|
- n = 3
|
186
|
|
- }
|
187
|
|
- if len(bestRides) > n {
|
188
|
|
- bestRides = bestRides[len(bestRides)-n:]
|
189
|
|
- }
|
|
168
|
+ if bestRide == nil || lenOfRide*bestTotal > total*bestLenOfRide {
|
|
169
|
+ bestLenOfRide = lenOfRide
|
|
170
|
+ bestTotal = total
|
|
171
|
+ bestRide = r
|
190
|
172
|
}
|
191
|
173
|
}
|
192
|
174
|
// if bestRide != nil {
|
193
|
175
|
// fmt.Printf("Picking %d %d -> %d %d\n", bestRide.a, bestRide.b, bestRide.x, bestRide.y)
|
194
|
176
|
// }
|
195
|
|
- if len(bestRides) != 0 {
|
196
|
|
- for _, br := range bestRides {
|
197
|
|
- r := br.r
|
198
|
|
- r.used = true
|
199
|
|
- oldC := *c
|
200
|
|
- c.Update(r)
|
201
|
|
- Sched.Add(c)
|
202
|
|
- // recursion 101
|
203
|
|
- Choose(cumulativeScore+c.score-oldC.score, depth+1)
|
204
|
|
- Sched.RemoveAtIndex(c.pqindex)
|
205
|
|
- // pqindex is meaningless now but it's ok
|
206
|
|
- // it will be fixed when c is added again
|
207
|
|
- *c = oldC
|
208
|
|
- r.used = false
|
|
177
|
+ if bestRide != nil {
|
|
178
|
+ r := c.pickClosestLate()
|
|
179
|
+ if r != nil {
|
|
180
|
+ bestRide = r
|
209
|
181
|
}
|
210
|
|
- } else {
|
211
|
|
- // another car may still have other rides
|
212
|
|
- Choose(cumulativeScore, depth)
|
213
|
182
|
}
|
214
|
|
- // add back the one we popped at beginning of function
|
|
183
|
+ return bestRide
|
|
184
|
+}
|
|
185
|
+
|
|
186
|
+func assign() bool {
|
|
187
|
+ c := Sched.Pop()
|
|
188
|
+ if c == nil {
|
|
189
|
+ return false
|
|
190
|
+ }
|
|
191
|
+ r := Choose(c)
|
|
192
|
+ if r == nil {
|
|
193
|
+ return true
|
|
194
|
+ }
|
|
195
|
+ r.used = true
|
|
196
|
+ c.Update(r)
|
215
|
197
|
Sched.Add(c)
|
|
198
|
+
|
|
199
|
+ return true
|
216
|
200
|
}
|
217
|
201
|
|
218
|
202
|
func solve() {
|
219
|
|
- rand.Seed(1)
|
220
|
|
-
|
221
|
203
|
sort.Sort(ByEndtime(Rides))
|
222
|
204
|
|
223
|
205
|
Sched = &prioq{}
|
|
@@ -234,17 +216,19 @@ func solve() {
|
234
|
216
|
Sched.Add(c)
|
235
|
217
|
}
|
236
|
218
|
|
237
|
|
- // start recursion
|
238
|
|
- Choose(0, 0)
|
|
219
|
+ for assign() {
|
|
220
|
+ }
|
239
|
221
|
|
|
222
|
+ totalScore := 0
|
240
|
223
|
for _, c := range Cars {
|
241
|
224
|
fmt.Fprintf(output, "%d", len(c.Rides))
|
242
|
225
|
for _, ri := range c.Rides {
|
243
|
226
|
fmt.Fprintf(output, " %d", ri)
|
244
|
227
|
}
|
245
|
228
|
fmt.Fprintf(output, "\n")
|
|
229
|
+ totalScore += c.score
|
246
|
230
|
}
|
247
|
|
- fmt.Printf("%d\n", bestTotalScore)
|
|
231
|
+ fmt.Printf("%d\n", totalScore)
|
248
|
232
|
}
|
249
|
233
|
|
250
|
234
|
func main() {
|
|
@@ -315,36 +299,31 @@ type prioq struct {
|
315
|
299
|
|
316
|
300
|
func (pq *prioq) Add(car *Car) {
|
317
|
301
|
pq.bintree = append(pq.bintree, car)
|
318
|
|
- pq.bintree[len(pq.bintree)-1].pqindex = len(pq.bintree) - 1
|
319
|
302
|
|
320
|
303
|
// Rebalance tree to respect invariant
|
321
|
304
|
var i = len(pq.bintree) - 1
|
322
|
305
|
var p = (i - 1) / 2
|
323
|
306
|
for p >= 0 && pq.bintree[p].Arrival > pq.bintree[i].Arrival {
|
324
|
307
|
pq.bintree[p], pq.bintree[i] = pq.bintree[i], pq.bintree[p]
|
325
|
|
- pq.bintree[p].pqindex = p
|
326
|
|
- pq.bintree[i].pqindex = i
|
327
|
308
|
i = p
|
328
|
309
|
p = (i - 1) / 2
|
329
|
310
|
}
|
330
|
311
|
}
|
331
|
312
|
|
332
|
|
-func (pq *prioq) RemoveAtIndex(k int) *Car {
|
|
313
|
+func (pq *prioq) Pop() *Car {
|
333
|
314
|
if len(pq.bintree) == 0 {
|
334
|
315
|
return nil
|
335
|
316
|
}
|
336
|
317
|
|
337
|
|
- if k == len(pq.bintree)-1 {
|
338
|
|
- elem := pq.bintree[k]
|
339
|
|
- pq.bintree = pq.bintree[:k]
|
|
318
|
+ if len(pq.bintree) == 1 {
|
|
319
|
+ elem := pq.bintree[0]
|
|
320
|
+ pq.bintree = pq.bintree[:0]
|
340
|
321
|
return elem
|
341
|
322
|
}
|
342
|
323
|
|
343
|
|
- pq.bintree[k].pqindex = -1
|
344
|
|
- elem := pq.bintree[k]
|
345
|
|
- // Put last element at hole
|
346
|
|
- pq.bintree[k] = pq.bintree[len(pq.bintree)-1]
|
347
|
|
- pq.bintree[k].pqindex = k
|
|
324
|
+ elem := pq.bintree[0]
|
|
325
|
+ // Put last element at root
|
|
326
|
+ pq.bintree[0] = pq.bintree[len(pq.bintree)-1]
|
348
|
327
|
// Remove last element
|
349
|
328
|
pq.bintree = pq.bintree[:len(pq.bintree)-1]
|
350
|
329
|
|
|
@@ -355,8 +334,7 @@ func (pq *prioq) RemoveAtIndex(k int) *Car {
|
355
|
334
|
|
356
|
335
|
// Rebalance tree to respect invariant
|
357
|
336
|
len := len(pq.bintree)
|
358
|
|
- i := k
|
359
|
|
- left, right := 0, 0
|
|
337
|
+ i, left, right := 0, 0, 0
|
360
|
338
|
for {
|
361
|
339
|
left = 2*i + 1
|
362
|
340
|
right = 2*i + 2
|
|
@@ -366,8 +344,6 @@ func (pq *prioq) RemoveAtIndex(k int) *Car {
|
366
|
344
|
break // Inferior to both children
|
367
|
345
|
} else {
|
368
|
346
|
pq.bintree[i], pq.bintree[left] = pq.bintree[left], pq.bintree[i]
|
369
|
|
- pq.bintree[i].pqindex = i
|
370
|
|
- pq.bintree[left].pqindex = left
|
371
|
347
|
i = left
|
372
|
348
|
}
|
373
|
349
|
} else {
|
|
@@ -375,8 +351,6 @@ func (pq *prioq) RemoveAtIndex(k int) *Car {
|
375
|
351
|
break // Inferior to both children
|
376
|
352
|
} else {
|
377
|
353
|
pq.bintree[i], pq.bintree[right] = pq.bintree[right], pq.bintree[i]
|
378
|
|
- pq.bintree[i].pqindex = i
|
379
|
|
- pq.bintree[right].pqindex = right
|
380
|
354
|
i = right
|
381
|
355
|
}
|
382
|
356
|
}
|
|
@@ -385,8 +359,6 @@ func (pq *prioq) RemoveAtIndex(k int) *Car {
|
385
|
359
|
break // Inferior to only child
|
386
|
360
|
}
|
387
|
361
|
pq.bintree[i], pq.bintree[left] = pq.bintree[left], pq.bintree[i]
|
388
|
|
- pq.bintree[i].pqindex = i
|
389
|
|
- pq.bintree[left].pqindex = left
|
390
|
362
|
i = left
|
391
|
363
|
} else { // No child
|
392
|
364
|
break
|
|
@@ -397,10 +369,6 @@ func (pq *prioq) RemoveAtIndex(k int) *Car {
|
397
|
369
|
return elem
|
398
|
370
|
}
|
399
|
371
|
|
400
|
|
-func (pq *prioq) Pop() *Car {
|
401
|
|
- return pq.RemoveAtIndex(0)
|
402
|
|
-}
|
403
|
|
-
|
404
|
372
|
func (pq *prioq) empty() bool {
|
405
|
373
|
return len(pq.bintree) == 0
|
406
|
374
|
}
|