-
-
Save rblaze/4563612 to your computer and use it in GitHub Desktop.
Специальная олимпиада-2: Bellman-Ford algorithm как первый шаг Johnson algorithm
Изначальная версия: haskell - 60 минут, C - две минуты.
Данные для обработки: http://spark-public.s3.amazonaws.com/algo2/datasets/large.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
const int infinity = 2147483647; | |
struct edge_t { | |
int v1; | |
int v2; | |
int cost; | |
}; | |
int | |
main(void) { | |
int nvertex, nedge; | |
scanf("%d %d\n", &nvertex, &nedge); | |
int nalledges = nedge + nvertex; | |
struct edge_t *edges = malloc(nalledges * sizeof(struct edge_t)); | |
// read input | |
for (int i = 0; i < nedge; i++) { | |
scanf("%d %d %d\n", &edges[i].v1, &edges[i].v2, &edges[i].cost); | |
} | |
// add edges from fake vertex | |
for (int i = 0; i < nvertex; i++) { | |
int idx = nedge + i; | |
edges[idx].v1 = 0; | |
edges[idx].v2 = i + 1; | |
edges[idx].cost = 0; | |
} | |
int *c1 = malloc((nvertex + 1) * sizeof(int)); | |
int *c2 = malloc((nvertex + 1) * sizeof(int)); | |
c1[0] = 0; | |
for (int i = 1; i < nvertex + 1; i++) { | |
c1[i] = infinity; | |
} | |
for (int n = 0; n < nvertex + 2; n++) { | |
for (int i = 0; i < nalledges; i++) { | |
int target = edges[i].v2; | |
int newcost = c1[edges[i].v1]; | |
if (newcost != infinity) { | |
newcost += edges[i].cost; | |
} | |
if (newcost < c1[target]) { | |
c1[target] = newcost; | |
} | |
} | |
if (n == nvertex) { | |
memcpy(c2, c1, (nvertex + 1) * sizeof(int)); | |
} | |
} | |
/* | |
for (int i = 0; i < nvertex + 1; i++) { | |
printf("%d\n", c1[i]); | |
} | |
*/ | |
if (memcmp(c1, c2, (nvertex + 1) * sizeof(int))) { | |
printf("Cycle\n"); | |
} else { | |
int v = c1[0]; | |
for (int i = 1; i < nvertex + 1; i++) { | |
if (c1[i] < v) { | |
v = c1[i]; | |
} | |
} | |
printf("Shortest path %d\n", v); | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE BangPatterns #-} | |
module Main where | |
import Control.DeepSeq | |
import Data.Functor | |
import Data.Int | |
import Data.Vector.Unboxed ((//)) | |
import qualified Data.Vector.Unboxed as V | |
--import Debug.Trace | |
type Vertex = Int | |
type Dist = Int32 | |
type Edge = (Vertex, Vertex, Dist) | |
type EdgeVec = V.Vector Edge | |
type CostVec = V.Vector Dist | |
readEdge :: String -> Edge | |
readEdge s = let [v1, v2, w] = words s | |
in (read v1, read v2, read w) | |
bfStep :: EdgeVec -> CostVec -> CostVec | |
bfStep edges !prev = V.unsafeAccumulate min prev $ V.map mincost edges | |
where | |
mincost :: Edge -> (Int, Int32) | |
mincost (s, h, c) = (h, cost s c) | |
cost w c = let precost = prev `V.unsafeIndex` w | |
in if precost == maxBound then maxBound else precost + c | |
mkEdgeVec :: Int -> [String] -> EdgeVec | |
mkEdgeVec nvert inp = V.unfoldr step (nvert, inp) | |
where | |
step (n, s:xs) = Just (readEdge s, (n, xs)) | |
step (0, []) = Nothing | |
step (!n, []) = Just ((0, n, 0), (n - 1, [])) | |
main :: IO() | |
main = do | |
header:body <- lines <$> getContents | |
let nvert = read $ head $ words header | |
let edgelist = mkEdgeVec nvert body | |
let bfbase = V.replicate (nvert + 1) maxBound // [(0, 0)] | |
print $ edgelist `deepseq` "running" | |
let bfout = iterate (bfStep edgelist) bfbase !! nvert | |
let bfcheck = bfStep edgelist bfout | |
let hasCycle = V.any id $ V.zipWith (/=) bfout bfcheck | |
putStrLn $ if hasCycle then "Cycle" else show $ V.minimum bfout |
voidlizard
commented
Jan 23, 2013
@rblaze было бы странно, если бы была существенная разница. accumulate пишет в мутабельный массив и фьюжн отрабатывает нормально:
$wbfStep :: EdgeVec -> CostVec -> Vector Dist
$wbfStep =
\ (w :: EdgeVec) (w1 :: CostVec) ->
let { Vector ipv ipv1 ipv2 ~ _ <- w1 `cast` ... } in
let { V_3 ipv3 ipv4 ipv5 ipv6 ~ _ <- w `cast` ... } in
let { Vector rb _ rb2 ~ _ <- ipv4 `cast` ... } in
let { Vector rb3 _ rb5 ~ _ <- ipv5 `cast` ... } in
let { Vector rb6 _ rb8 ~ _ <- ipv6 `cast` ... } in
runSTRep
(\ (@ s) (s :: State# s) ->
case >=# ipv1 0 of _ {
False -> (lvl3 ipv1) `cast` ...;
True ->
let { (# s'#, arr# #) ~ _
<- newByteArray# (*# ipv1 4) (s `cast` ...)
} in
letrec {
$s$wa :: Int# -> State# s -> (# State# s, () #)
$s$wa =
\ (sc :: Int#) (sc1 :: State# s) ->
case >=# sc ipv3 of _ {
False ->
let { __DEFAULT ~ wild6 <- indexIntArray# rb5 (+# rb3 sc) } in
let { (# s1#, x# #) ~ _
<- readIntArray# arr# wild6 (sc1 `cast` ...)
} in
let { __DEFAULT ~ wild8 <- indexIntArray# rb2 (+# rb sc) } in
case indexIntArray# ipv2 (+# ipv wild8) of wild9 {
__DEFAULT ->
let { __DEFAULT ~ wild10 <- indexIntArray# rb8 (+# rb6 sc) } in
let {
y1 :: Int#
y1 = +# wild9 wild10 } in
case <=# x# y1 of _ {
False ->
let { __DEFAULT ~ s1
<- (writeIntArray# arr# wild6 y1 s1#) `cast` ...
} in
$s$wa (+# sc 1) s1;
True ->
let { __DEFAULT ~ s1
<- (writeIntArray# arr# wild6 x# s1#) `cast` ...
} in
$s$wa (+# sc 1) s1
};
2147483647 ->
let { __DEFAULT ~ s1
<- (writeIntArray# arr# wild6 x# s1#) `cast` ...
} in
$s$wa (+# sc 1) s1
};
True -> (# sc1, () #)
}; } in
let { (# new_s1, _ #) ~ _
<- $s$wa
0
((copyByteArray# ipv2 (*# ipv 4) arr# 0 (*# ipv1 4) s'#)
`cast` ...)
} in
let { (# s'#1, arr'# #) ~ _
<- unsafeFreezeByteArray# arr# (new_s1 `cast` ...)
} in
(# s'#1 `cast` ..., (Vector 0 ipv1 arr'#) `cast` ... #)
})
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment