Start
This commit is contained in:
29
.clang-format
Normal file
29
.clang-format
Normal file
@@ -0,0 +1,29 @@
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
|
||||
BreakBeforeBraces: Attach
|
||||
ColumnLimit: 80
|
||||
SpaceBeforeParens: ControlStatements
|
||||
PointerAlignment: Right
|
||||
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^"threads/.*\.h"'
|
||||
Priority: 1
|
||||
- Regex: '^"userprog/.*\.h"'
|
||||
Priority: 2
|
||||
- Regex: '^"devices/.*\.h"'
|
||||
Priority: 3
|
||||
- Regex: '^"filesys/.*\.h"'
|
||||
Priority: 4
|
||||
- Regex: '^".*\.h"'
|
||||
Priority: 5
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 6
|
||||
- Regex: '^<.*'
|
||||
Priority: 7
|
||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
build/
|
||||
.cache
|
||||
.compile_commands.json
|
||||
|
||||
.DS_Store
|
||||
226
Makefile
Normal file
226
Makefile
Normal file
@@ -0,0 +1,226 @@
|
||||
SHELL = /bin/bash
|
||||
|
||||
CXX = g++
|
||||
|
||||
SRC_DIR = src
|
||||
GEN_DIR = generator
|
||||
VAL_DIR = validator
|
||||
INC_DIR = include
|
||||
CHK_DIR = checker
|
||||
|
||||
BUILD_DIR = build
|
||||
BUILD_TARGET_DIR = $(BUILD_DIR)/target
|
||||
BUILD_GEN_DIR = $(BUILD_DIR)/gen
|
||||
BUILD_VAL_DIR = $(BUILD_DIR)/val
|
||||
BUILD_CHK_DIR = $(BUILD_DIR)/chk
|
||||
LOG_DIR = $(BUILD_DIR)/logs
|
||||
|
||||
BUILD_IN_DIR = $(BUILD_DIR)/input
|
||||
BUILD_OUT_A_DIR = $(BUILD_DIR)/$(SOL_A)_out
|
||||
BUILD_OUT_B_DIR = $(BUILD_DIR)/$(SOL_B)_out
|
||||
|
||||
DIRS = $(BUILD_DIR) $(BUILD_TARGET_DIR) $(BUILD_GEN_DIR) $(BUILD_VAL_DIR) $(BUILD_CHK_DIR) $(LOG_DIR) $(BUILD_IN_DIR) $(BUILD_OUT_A_DIR) $(BUILD_OUT_B_DIR)
|
||||
|
||||
CXXFLAGS = -Wall -O2 -std=c++2a -I$(INC_DIR)
|
||||
GENFLAGS = -N $(N) -M $(M) -pm $(pm)
|
||||
|
||||
SRC_MAIN_FILES = $(wildcard $(SRC_DIR)/*/main.cpp)
|
||||
SOLS_EXE = $(patsubst $(SRC_DIR)/%/main.cpp, $(BUILD_TARGET_DIR)/%, $(SRC_MAIN_FILES))
|
||||
|
||||
SOL_A ?= bsb
|
||||
SOL_B ?= dijk
|
||||
SOL_A_EXE = $(BUILD_TARGET_DIR)/$(SOL_A)
|
||||
SOL_B_EXE = $(BUILD_TARGET_DIR)/$(SOL_B)
|
||||
|
||||
GEN_SRCS = $(wildcard $(GEN_DIR)/*.cpp)
|
||||
GENS_EXE = $(patsubst $(GEN_DIR)/%.cpp, $(BUILD_GEN_DIR)/%, $(GEN_SRCS))
|
||||
|
||||
gen ?= gen1
|
||||
GEN_TO_RUN = $(BUILD_GEN_DIR)/$(gen)
|
||||
|
||||
VAL_EXE = $(BUILD_VAL_DIR)/validator
|
||||
CHK_EXE = $(BUILD_CHK_DIR)/checker
|
||||
|
||||
PADDED_ID = $(shell printf "%05d" $(id))
|
||||
IN_FILE = $(BUILD_IN_DIR)/input$(PADDED_ID)
|
||||
OUT_A_FILE = $(BUILD_OUT_A_DIR)/$(SOL_A)$(PADDED_ID).out
|
||||
OUT_B_FILE = $(BUILD_OUT_B_DIR)/$(SOL_B)$(PADDED_ID).out
|
||||
|
||||
TEST_COUNT ?= 100
|
||||
N ?= 1000
|
||||
M ?= 5000
|
||||
pm ?= 0.1
|
||||
|
||||
.PHONY: all
|
||||
all: $(SOLS_EXE) $(GENS_EXE) $(VAL_EXE) $(CHK_EXE) $(DIRS)
|
||||
@echo "All executables compiled in $(BUILD_DIR)/"
|
||||
|
||||
$(BUILD_DIR) $(BUILD_TARGET_DIR) $(BUILD_GEN_DIR) $(BUILD_VAL_DIR) $(BUILD_CHK_DIR) $(LOG_DIR) $(BUILD_IN_DIR) $(BUILD_OUT_A_DIR) $(BUILD_OUT_B_DIR):
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_TARGET_DIR)/%: $(SRC_DIR)/%/main.cpp | $(BUILD_TARGET_DIR)
|
||||
@echo "Compiling Solution $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_GEN_DIR)/%: $(GEN_DIR)/%.cpp | $(BUILD_GEN_DIR)
|
||||
@echo "Compiling Generator $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_VAL_DIR)/%: $(VAL_DIR)/%.cpp | $(BUILD_VAL_DIR)
|
||||
@echo "Compiling Validator $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_CHK_DIR)/%: $(CHK_DIR)/%.cpp | $(BUILD_CHK_DIR)
|
||||
@echo "Compiling Checker $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
.PRECIOUS: $(BUILD_IN_DIR)/input%
|
||||
$(BUILD_IN_DIR)/input%: $(GEN_TO_RUN) | $(BUILD_IN_DIR)
|
||||
@echo "--- Generating Input: $@ (Using [$(gen)]) ---"
|
||||
@SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 32); \
|
||||
echo "Using Seed: $$SEED" >&2; \
|
||||
./$(GEN_TO_RUN) $(GENFLAGS) "$$SEED" > $@
|
||||
|
||||
$(BUILD_OUT_A_DIR)/$(SOL_A)%.out: $(BUILD_IN_DIR)/input% $(SOL_A_EXE) | $(BUILD_OUT_A_DIR)
|
||||
@echo "--- Running $(SOL_A) (ID: $*) ---"
|
||||
@time ./$(SOL_A_EXE) < $< > $@
|
||||
|
||||
$(BUILD_OUT_B_DIR)/$(SOL_B)%.out: $(BUILD_IN_DIR)/input% $(SOL_B_EXE) | $(BUILD_OUT_B_DIR)
|
||||
@echo "--- Running $(SOL_B) (ID: $*) ---"
|
||||
@time ./$(SOL_B_EXE) < $< > $@
|
||||
|
||||
.PHONY: gen
|
||||
gen: all
|
||||
ifeq ($(id),)
|
||||
@echo "Error: 'make gen' requires an 'id' variable."
|
||||
@echo "Usage: make gen id=<test_id> [gen=gen_name]"
|
||||
@exit 1
|
||||
else
|
||||
@$(MAKE) --no-print-directory $(IN_FILE) id=$(id) gen=$(gen) N=$(N) M=$(M)
|
||||
@echo "--- Generated $(IN_FILE) ---"
|
||||
endif
|
||||
|
||||
# # 레거시 gen1 타겟
|
||||
# .PHONY: gen1
|
||||
# gen1: $(BUILD_GEN_DIR)/gen1
|
||||
# @echo "--- gen1 : Generating 1 test case (DEPRECATED: use 'make gen id=1') ---"
|
||||
# @SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 32); \
|
||||
# echo "./$(BUILD_GEN_DIR)/gen1 -N $(N) -M $(M) $$SEED | tee $(BUILD_IN_DIR)/input_legacy"; \
|
||||
# ./$(BUILD_GEN_DIR)/gen1 -N $(N) -M $(M) $$SEED | tee $(BUILD_IN_DIR)/input_legacy
|
||||
|
||||
# # 레거시 gen1-silence 타겟
|
||||
# .PHONY: gen1-silence
|
||||
# gen1-silence: $(BUILD_GEN_DIR)/gen1
|
||||
# @echo "--- gen1 : Generating 1 test case (DEPRECATED: use 'make gen id=1') ---"
|
||||
# @SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 32); \
|
||||
# ./$(BUILD_GEN_DIR)/gen1 -N $(N) -M $(M) "$$SEED" > $(BUILD_IN_DIR)/input_legacy
|
||||
|
||||
.PHONY: val
|
||||
val: all $(VAL_EXE)
|
||||
ifeq ($(id),)
|
||||
@echo "Error: 'make val' requires an 'id' variable."
|
||||
@echo "Usage: make val id=<test_id>"
|
||||
@exit 1
|
||||
else
|
||||
@$(MAKE) --no-print-directory $(IN_FILE) id=$(id) gen=$(gen) N=$(N) M=$(M)
|
||||
@echo "--- Validating $(IN_FILE) (ID=$(id)) ---"
|
||||
@./$(VAL_EXE) < $(IN_FILE)
|
||||
@echo "Validator OK."
|
||||
endif
|
||||
|
||||
.PHONY: check
|
||||
check: all $(CHK_EXE)
|
||||
ifeq ($(id),)
|
||||
@echo "Error: 'make check' requires an 'id' variable."
|
||||
@echo "Usage: make check id=<test_id>"
|
||||
@exit 1
|
||||
else
|
||||
@echo "--- Checking ID=$(id) ---"
|
||||
@$(MAKE) --no-print-directory $(OUT_A_FILE) id=$(id) gen=$(gen) SOL_A=$(SOL_A) GENARGS=$(GENARGS)
|
||||
@$(MAKE) --no-print-directory $(OUT_B_FILE) id=$(id) gen=$(gen) SOL_B=$(SOL_B) GENARGS=$(GENARGS)
|
||||
@echo "--- Comparing Outputs (ID=$(id)) ---"
|
||||
@./$(CHK_EXE) $(IN_FILE) $(OUT_A_FILE) $(OUT_B_FILE) || ( \
|
||||
echo "WA (Wrong Answer): Checker found an issue!" && \
|
||||
echo "Input: $(IN_FILE)" && \
|
||||
exit 1 \
|
||||
)
|
||||
@echo "OK: ID=$(id) outputs match!"
|
||||
endif
|
||||
|
||||
.PHONY: test
|
||||
test: all $(LOG_DIR) $(BUILD_OUT_A_DIR) $(BUILD_OUT_B_DIR)
|
||||
ifeq ($(id),)
|
||||
@echo "--- Running $(TEST_COUNT) tests (Comparing $(SOL_A) vs $(SOL_B)) ---"
|
||||
@echo "--- Using Generator [$(gen)] (N=$(N), M=$(M)) ---"
|
||||
@LOG_FILE=$(LOG_DIR)/test_run_$$(date +%Y%m%d_%H%M%S).log; \
|
||||
echo "--- Logging to $${LOG_FILE} ---"; \
|
||||
script -q /dev/null /bin/bash -c ' \
|
||||
set -o pipefail; \
|
||||
for i in {1..$(TEST_COUNT)}; do \
|
||||
IN_FILE_LOOP=$(BUILD_IN_DIR)/input$$(printf "%05d" $$i); \
|
||||
OUT_A_FILE_LOOP=$(BUILD_OUT_A_DIR)/$(SOL_A)$$(printf "%05d" $$i).out; \
|
||||
OUT_B_FILE_LOOP=$(BUILD_OUT_B_DIR)/$(SOL_B)$$(printf "%05d" $$i).out; \
|
||||
\
|
||||
if [ ! -f $$IN_FILE_LOOP ]; then \
|
||||
SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd "a-zA-Z0-9" | head -c 32); \
|
||||
printf "Test %4d (Seed: %s): " "$$i" "$$SEED"; \
|
||||
./$(GEN_TO_RUN) -N $(N) -M $(M) "$$SEED" > $$IN_FILE_LOOP; \
|
||||
printf "(GEN) "; \
|
||||
else \
|
||||
printf "Test %4d (Seed: EXISTING): " "$$i"; \
|
||||
fi; \
|
||||
\
|
||||
printf "$(SOL_A): "; \
|
||||
( TIMEFORMAT=%R; time ./$(SOL_A_EXE) < $$IN_FILE_LOOP > $$OUT_A_FILE_LOOP ) 2>&1 | tr "\n" " " ; \
|
||||
printf "$(SOL_B): "; \
|
||||
( TIMEFORMAT=%R; time ./$(SOL_B_EXE) < $$IN_FILE_LOOP > $$OUT_B_FILE_LOOP ) 2>&1 | tr "\n" " " ; \
|
||||
printf "\t CHK: "; \
|
||||
( ./$(CHK_EXE) $$IN_FILE_LOOP $$OUT_A_FILE_LOOP $$OUT_B_FILE_LOOP ) 2>&1 || { printf "\nWA! (Input: $$IN_FILE_LOOP)\n"; echo "Input saved to $$IN_FILE_LOOP"; exit 1; }; \
|
||||
done; \
|
||||
echo "--- All $(TEST_COUNT) tests passed! ---"; \
|
||||
' | tee $${LOG_FILE}; \
|
||||
if [ $${PIPESTATUS[0]} -ne 0 ]; then \
|
||||
printf "\n--- TESTS FAILED! See %s ---\n" "$${LOG_FILE}"; \
|
||||
exit 1; \
|
||||
fi
|
||||
else
|
||||
@echo "--- Running single test for ID=$(id) ---"
|
||||
@$(MAKE) --no-print-directory check id=$(id) gen=$(gen) SOL_A=$(SOL_A) SOL_B=$(SOL_B) N=$(N) M=$(M)
|
||||
endif
|
||||
|
||||
# 단일 파일 벤치마크 (e.g., make bench id=5)
|
||||
.PHONY: bench
|
||||
bench: all
|
||||
ifeq ($(id),)
|
||||
@echo "Error: 'make bench' requires an 'id' variable."
|
||||
@exit 1
|
||||
else
|
||||
@$(MAKE) --no-print-directory $(IN_FILE) id=$(id) gen=$(gen) N=$(N) M=$(M)
|
||||
@echo "--- Benchmarking $(SOL_A_EXE) with $(IN_FILE) (ID=$(id)) ---"
|
||||
@time ./$(SOL_A_EXE) < $(IN_FILE) > $(OUT_A_FILE)
|
||||
endif
|
||||
|
||||
.PHONY: format
|
||||
format:
|
||||
@echo "--- Formatting all C/C++ files ---"
|
||||
@find $(SRC_DIR) $(GEN_DIR) $(VAL_DIR) $(CHK_DIR) $(INC_DIR) -type f \( -name "*.cpp" -o -name "*.c" -o -name "*.hpp" -o -name "*.h" \) -print0 | xargs -0 clang-format -i
|
||||
@echo "Formatting complete."
|
||||
|
||||
.PHONY: clean-outputs
|
||||
clean-outputs:
|
||||
@echo "Cleaning up $(BUILD_OUT_A_DIR)/ and $(BUILD_OUT_B_DIR)/..."
|
||||
@rm -rf $(BUILD_OUT_A_DIR) $(BUILD_OUT_B_DIR)
|
||||
|
||||
.PHONY: clean-inputs
|
||||
clean-inputs:
|
||||
@echo "Cleaning up $(BUILD_IN_DIR)/..."
|
||||
@rm -rf $(BUILD_IN_DIR)
|
||||
|
||||
.PHONY: clean-tests
|
||||
clean-tests: clean-inputs clean-outputs
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Cleaning up $(BUILD_DIR)/..."
|
||||
@rm -rf $(BUILD_DIR)
|
||||
159
Makefile2
Normal file
159
Makefile2
Normal file
@@ -0,0 +1,159 @@
|
||||
CXX = g++
|
||||
|
||||
SRC_DIR = src
|
||||
GEN_DIR = generator
|
||||
VAL_DIR = validator
|
||||
INC_DIR = include
|
||||
CHK_DIR = checker
|
||||
|
||||
BUILD_DIR = build
|
||||
BUILD_TARGET_DIR = $(BUILD_DIR)/target
|
||||
BUILD_GEN_DIR = $(BUILD_DIR)/gen
|
||||
BUILD_VAL_DIR = $(BUILD_DIR)/val
|
||||
BUILD_CHK_DIR = $(BUILD_DIR)/chk
|
||||
|
||||
CXXFLAGS = -Wall -O2 -std=c++2a -I$(INC_DIR)
|
||||
|
||||
BSB_EXE = $(BUILD_TARGET_DIR)/bsb
|
||||
DIJK_EXE = $(BUILD_TARGET_DIR)/dijk
|
||||
|
||||
GEN1_EXE = $(BUILD_GEN_DIR)/gen1
|
||||
GEN2_EXE = $(BUILD_GEN_DIR)/gen2
|
||||
GENS = $(GEN1_EXE) $(GEN2_EXE)
|
||||
|
||||
GEN_DEFAULT = $(GEN1_EXE)
|
||||
|
||||
VAL_EXE = $(BUILD_VAL_DIR)/validator
|
||||
|
||||
CHK_EXE = $(BUILD_CHK_DIR)/checker
|
||||
|
||||
IN = $(BUILD_DIR)/input.txt
|
||||
OUT_DIJK = $(BUILD_DIR)/dijk.out
|
||||
OUT_BSB = $(BUILD_DIR)/bsb.out
|
||||
|
||||
TEST_COUNT = 100
|
||||
|
||||
.PHONY: all
|
||||
all: $(BSB_EXE) $(DIJK_EXE) $(GEN1_EXE) $(GEN2_EXE) $(VAL_EXE) $(CHK_EXE)
|
||||
@echo "All executables compiled in $(BUILD_DIR)/"
|
||||
|
||||
$(BUILD_TARGET_DIR)/%: $(SRC_DIR)/%/main.cpp | $(BUILD_TARGET_DIR)
|
||||
@echo "Compiling Solution $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_GEN_DIR)/%: $(GEN_DIR)/%.cpp | $(BUILD_GEN_DIR)
|
||||
@echo "Compiling Generator $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_VAL_DIR)/%: $(VAL_DIR)/%.cpp | $(BUILD_VAL_DIR)
|
||||
@echo "Compiling Validator $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_CHK_DIR)/%: $(CHK_DIR)/%.cpp | $(BUILD_CHK_DIR)
|
||||
@echo "Compiling Checker $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_DIR):
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_TARGET_DIR): | $(BUILD_DIR)
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_GEN_DIR): | $(BUILD_DIR)
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_VAL_DIR): | $(BUILD_DIR)
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_CHK_DIR): | $(BUILD_DIR)
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
|
||||
|
||||
.PHONY: gen1
|
||||
gen1: $(GENS)
|
||||
@echo "--- gen1 : Generating 1 test case ---"
|
||||
@SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd '[[:graph:]]' | head -c 32); \
|
||||
echo "./$(GEN1_EXE) -N $(N) -pm $(pm) $$SEED | tee $(IN)"; \
|
||||
./$(GEN1_EXE) -N $(N) -pm $(pm) $$SEED | tee $(IN)
|
||||
|
||||
.PHONY: gen1-silence
|
||||
gen1-silence: $(GENS)
|
||||
@echo "--- gen1 : Generating 1 test case ---"
|
||||
@SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd '[[:graph:]]' | head -c 32); \
|
||||
echo "./$(GEN1_EXE) -N $(N) -M $(M) $$SEED > $(IN)"; \
|
||||
./$(GEN1_EXE) -N $(N) -M $(M) $$SEED > $(IN)
|
||||
|
||||
.PHONY: val
|
||||
val: $(VAL_EXE) | gen1-silence
|
||||
@echo "--- Validating test case $(IN)..."
|
||||
# @./$(VAL_EXE) < $(IN)
|
||||
@echo "Validator OK."
|
||||
|
||||
.PHONY: check
|
||||
check: all val
|
||||
@echo "--- Running: $(DIJK_EXE)"
|
||||
@./$(DIJK_EXE) < $(IN) > $(OUT_DIJK)
|
||||
@echo "--- Running: $(BSB_EXE)"
|
||||
@./$(BSB_EXE) < $(IN) > $(OUT_BSB)
|
||||
@echo "--- Comparing Outputs (using $(CHK_EXE)) ---"
|
||||
@./$(CHK_EXE) $(IN) $(OUT_DIJK) $(OUT_BSB) || ( \
|
||||
echo "WA (Wrong Answer): Checker found an issue!" && \
|
||||
echo "Input is saved to $(IN)" && \
|
||||
exit 1 \
|
||||
)
|
||||
@echo "OK: Outputs match!"
|
||||
|
||||
# .PHONY: check
|
||||
# check: all val
|
||||
# @echo "--- Running Solution: $(BSB_EXE)"
|
||||
# @./$(BSB_EXE) < $(IN) > $(OUT_SOL)
|
||||
# @echo "--- Running Brute Force: $(DIJK_EXE)"
|
||||
# @./$(DIJK_EXE) < $(IN) > $(OUT_BRUTE)
|
||||
# @echo "--- Comparing Outputs ---"
|
||||
# @diff -w $(OUT_SOL) $(OUT_BRUTE) || ( \
|
||||
# echo "WA (Wrong Answer): Outputs differ!" && \
|
||||
# echo "Input is saved to $(IN)" && \
|
||||
# exit 1 \
|
||||
# )
|
||||
# @echo "OK: Outputs match!"
|
||||
|
||||
.PHONY: test
|
||||
test: all
|
||||
@echo "--- Running $(TEST_COUNT) tests ---"
|
||||
@for i in {1..$(TEST_COUNT)}; do \
|
||||
SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd '[[:graph:]]' | head -c 32); \
|
||||
printf "Test %4d \t(Seed: %s): " "$$i" "$$SEED"; \
|
||||
./$(GEN_DEFAULT) -N $(N) -M $(M) $$SEED > $(IN); \
|
||||
printf "(TEST GEN SUCCEED) "; \
|
||||
./$(DIJK_EXE) < $(IN) > $(OUT_DIJK); \
|
||||
printf "(DIJK FIN) "; \
|
||||
./$(BSB_EXE) < $(IN) > $(OUT_BSB); \
|
||||
printf "(BSB FIN):\t"; \
|
||||
./$(CHK_EXE) $(IN) $(OUT_BSB) $(OUT_DIJK) > /dev/null || { echo "WA! (Seed: $$SEED)"; echo "Input saved to $(IN)"; exit 1; }; \
|
||||
done
|
||||
@echo "--- All $(TEST_COUNT) tests passed! ---"
|
||||
# ./$(VAL_EXE) < $(IN) > /dev/null || { echo "Validator Error! (Seed: $$SEED)"; echo "Input saved to $(IN)"; break; };
|
||||
|
||||
|
||||
.PHONY: bench
|
||||
bench: $(BSB_EXE) val
|
||||
@echo "--- Benchmarking $(BSB_EXE) with $(IN) ---"
|
||||
@time ./$(BSB_EXE) < $(IN) > $(OUT_BSB)
|
||||
|
||||
.PHONY: format
|
||||
format:
|
||||
@echo "--- Formatting all C/C++ files ---"
|
||||
@find $(SRC_DIR) $(GEN_DIR) $(VAL_DIR) $(CHK_DIR) $(INC_DIR) -type f \( -name "*.cpp" -o -name "*.c" -o -name "*.hpp" -o -name "*.h" \) -print0 | xargs -0 clang-format -i
|
||||
@echo "Formatting complete."
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Cleaning up $(BUILD_DIR)/..."
|
||||
@rm -r build
|
||||
|
||||
159
Makefile3
Normal file
159
Makefile3
Normal file
@@ -0,0 +1,159 @@
|
||||
CXX = g++
|
||||
|
||||
SRC_DIR = src
|
||||
GEN_DIR = generator
|
||||
VAL_DIR = validator
|
||||
INC_DIR = include
|
||||
CHK_DIR = checker
|
||||
|
||||
BUILD_DIR = build
|
||||
BUILD_TARGET_DIR = $(BUILD_DIR)/target
|
||||
BUILD_GEN_DIR = $(BUILD_DIR)/gen
|
||||
BUILD_VAL_DIR = $(BUILD_DIR)/val
|
||||
BUILD_CHK_DIR = $(BUILD_DIR)/chk
|
||||
|
||||
CXXFLAGS = -Wall -O2 -std=c++2a -I$(INC_DIR)
|
||||
|
||||
BSB_EXE = $(BUILD_TARGET_DIR)/bsb
|
||||
DIJK_EXE = $(BUILD_TARGET_DIR)/dijk
|
||||
|
||||
GEN1_EXE = $(BUILD_GEN_DIR)/gen1
|
||||
GEN2_EXE = $(BUILD_GEN_DIR)/gen2
|
||||
GENS = $(GEN1_EXE) $(GEN2_EXE)
|
||||
|
||||
GEN_DEFAULT = $(GEN1_EXE)
|
||||
|
||||
VAL_EXE = $(BUILD_VAL_DIR)/validator
|
||||
|
||||
CHK_EXE = $(BUILD_CHK_DIR)/checker
|
||||
|
||||
IN = $(BUILD_DIR)/input.txt
|
||||
OUT_DIJK = $(BUILD_DIR)/dijk.out
|
||||
OUT_BSB = $(BUILD_DIR)/bsb.out
|
||||
|
||||
TEST_COUNT = 100
|
||||
|
||||
.PHONY: all
|
||||
all: $(BSB_EXE) $(DIJK_EXE) $(GEN1_EXE) $(GEN2_EXE) $(VAL_EXE) $(CHK_EXE)
|
||||
@echo "All executables compiled in $(BUILD_DIR)/"
|
||||
|
||||
$(BUILD_TARGET_DIR)/%: $(SRC_DIR)/%/main.cpp | $(BUILD_TARGET_DIR)
|
||||
@echo "Compiling Solution $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_GEN_DIR)/%: $(GEN_DIR)/%.cpp | $(BUILD_GEN_DIR)
|
||||
@echo "Compiling Generator $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_VAL_DIR)/%: $(VAL_DIR)/%.cpp | $(BUILD_VAL_DIR)
|
||||
@echo "Compiling Validator $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_CHK_DIR)/%: $(CHK_DIR)/%.cpp | $(BUILD_CHK_DIR)
|
||||
@echo "Compiling Checker $< -> $@"
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
$(BUILD_DIR):
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_TARGET_DIR): | $(BUILD_DIR)
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_GEN_DIR): | $(BUILD_DIR)
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_VAL_DIR): | $(BUILD_DIR)
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
$(BUILD_CHK_DIR): | $(BUILD_DIR)
|
||||
@echo "Creating directory: $@"
|
||||
@mkdir -p $@
|
||||
|
||||
|
||||
|
||||
.PHONY: gen1
|
||||
gen1: $(GENS)
|
||||
@echo "--- gen1 : Generating 1 test case ---"
|
||||
@SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd '[[:graph:]]' | head -c 32); \
|
||||
echo "./$(GEN1_EXE) -N $(N) -pm $(pm) $$SEED | tee $(IN)"; \
|
||||
./$(GEN1_EXE) -N $(N) -pm $(pm) $$SEED | tee $(IN)
|
||||
|
||||
.PHONY: gen1-silence
|
||||
gen1-silence: $(GENS)
|
||||
@echo "--- gen1 : Generating 1 test case ---"
|
||||
@SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd '[[:graph:]]' | head -c 32); \
|
||||
echo "./$(GEN1_EXE) -N $(N) -M $(M) $$SEED > $(IN)"; \
|
||||
./$(GEN1_EXE) -N $(N) -M $(M) $$SEED > $(IN)
|
||||
|
||||
.PHONY: val
|
||||
val: $(VAL_EXE) | gen1-silence
|
||||
@echo "--- Validating test case $(IN)..."
|
||||
# @./$(VAL_EXE) < $(IN)
|
||||
@echo "Validator OK."
|
||||
|
||||
.PHONY: check
|
||||
check: all val
|
||||
@echo "--- Running: $(DIJK_EXE)"
|
||||
@time ./$(DIJK_EXE) < $(IN) > $(OUT_DIJK)
|
||||
@echo "--- Running: $(BSB_EXE)"
|
||||
@time ./$(BSB_EXE) < $(IN) > $(OUT_BSB)
|
||||
@echo "--- Comparing Outputs (using $(CHK_EXE)) ---"
|
||||
@./$(CHK_EXE) $(IN) $(OUT_DIJK) $(OUT_BSB) || ( \
|
||||
echo "WA (Wrong Answer): Checker found an issue!" && \
|
||||
echo "Input is saved to $(IN)" && \
|
||||
exit 1 \
|
||||
)
|
||||
@echo "OK: Outputs match!"
|
||||
|
||||
# .PHONY: check
|
||||
# check: all val
|
||||
# @echo "--- Running Solution: $(BSB_EXE)"
|
||||
# @./$(BSB_EXE) < $(IN) > $(OUT_SOL)
|
||||
# @echo "--- Running Brute Force: $(DIJK_EXE)"
|
||||
# @./$(DIJK_EXE) < $(IN) > $(OUT_BRUTE)
|
||||
# @echo "--- Comparing Outputs ---"
|
||||
# @diff -w $(OUT_SOL) $(OUT_BRUTE) || ( \
|
||||
# echo "WA (Wrong Answer): Outputs differ!" && \
|
||||
# echo "Input is saved to $(IN)" && \
|
||||
# exit 1 \
|
||||
# )
|
||||
# @echo "OK: Outputs match!"
|
||||
|
||||
.PHONY: test
|
||||
test: all
|
||||
@echo "--- Running $(TEST_COUNT) tests ---"
|
||||
@for i in {1..$(TEST_COUNT)}; do \
|
||||
SEED=$$(export LC_ALL=C; cat /dev/urandom | tr -cd '[[:graph:]]' | head -c 32); \
|
||||
printf "Test %4d (Seed: %s): " "$$i" "$$SEED"; \
|
||||
./$(GEN_DEFAULT) -N $(N) -M $(M) $$SEED > $(IN); \
|
||||
printf "(GEN) "; \
|
||||
printf "DIJK: "; \
|
||||
( TIMEFORMAT=%R; time ./$(DIJK_EXE) < $(IN) > $(OUT_DIJK) ) 2>&1 | tr '\n' ' ' ; \
|
||||
printf "BSB: "; \
|
||||
( TIMEFORMAT=%R; time ./$(BSB_EXE) < $(IN) > $(OUT_BSB) ) 2>&1 | tr '\n' ' ' ; \
|
||||
printf "CHK: "; \
|
||||
( ./$(CHK_EXE) $(IN) $(OUT_BSB) $(OUT_DIJK) > /dev/null ) 2>&1 || { printf "\nWA! (Seed: %s)\n" "$$SEED"; echo "Input saved to $(IN)"; exit 1; }; \
|
||||
done
|
||||
@echo "--- All $(TEST_COUNT) tests passed! ---"
|
||||
# ./$(VAL_EXE) < $(IN) > /dev/null || { echo "Validator Error! (Seed: $$SEED)"; echo "Input saved to $(IN)"; break; };
|
||||
|
||||
|
||||
.PHONY: bench
|
||||
bench: $(BSB_EXE) val
|
||||
@echo "--- Benchmarking $(BSB_EXE) with $(IN) ---"
|
||||
@time ./$(BSB_EXE) < $(IN) > $(OUT_BSB)
|
||||
|
||||
.PHONY: format
|
||||
format:
|
||||
@echo "--- Formatting all C/C++ files ---"
|
||||
@find $(SRC_DIR) $(GEN_DIR) $(VAL_DIR) $(CHK_DIR) $(INC_DIR) -type f \( -name "*.cpp" -o -name "*.c" -o -name "*.hpp" -o -name "*.h" \) -print0 | xargs -0 clang-format -i
|
||||
@echo "Formatting complete."
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Cleaning up $(BUILD_DIR)/..."
|
||||
@rm -r build
|
||||
54
checker/checker.cpp
Normal file
54
checker/checker.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "testlib.h"
|
||||
|
||||
using ll = long long;
|
||||
|
||||
const double eps = 1e-5;
|
||||
|
||||
double parseDouble(const std::string &s, InStream &stream) {
|
||||
double result;
|
||||
// 1. sscanf로 숫자 파싱 시도
|
||||
if (sscanf(s.c_str(), "%lf", &result) == 1) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. sscanf 실패 시, 특수 값인지 문자열 비교
|
||||
if (s == "inf" || s == "+inf" || s == "INF" || s == "+INF")
|
||||
return std::numeric_limits<double>::infinity();
|
||||
if (s == "-inf" || s == "-INF")
|
||||
return -std::numeric_limits<double>::infinity();
|
||||
if (s == "nan" || s == "NaN" || s == "NAN")
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
// 3. 숫자도 아니고 특수 값도 아니면 오류 종료
|
||||
// 'stream'을 사용해 어느 파일이 문제인지 정확히 리포트
|
||||
stream.quitf(_fail, "Expected double, but %s found", s.c_str());
|
||||
return 0; // Unreachable
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
registerTestlibCmd(argc, argv);
|
||||
|
||||
ll n = inf.readLong(1, (ll)1e9);
|
||||
|
||||
for (ll line = 1; line <= n; line++) {
|
||||
double j = parseDouble(ans.readToken(), ans);
|
||||
double p = parseDouble(ouf.readToken(), ouf);
|
||||
|
||||
ans.readEoln();
|
||||
ouf.readEoln();
|
||||
|
||||
if (!doubleCompare(j, p, eps)) {
|
||||
quitf(_wa,
|
||||
"%lld-th line: expected '%.7f', found '%.7f'. "
|
||||
"Absolute/Relative error > %.0e",
|
||||
line, j, p, eps);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ans.eof())
|
||||
quitf(_pe, "Expected EOF in judge output, but found more data");
|
||||
if (!ouf.eof())
|
||||
quitf(_pe, "Expected EOF in bsb output, but found more data");
|
||||
|
||||
quitf(_ok, "OK: %lld lines compared within %.0e epsilon.", n, eps);
|
||||
}
|
||||
18
compile_commands.json
Normal file
18
compile_commands.json
Normal file
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"arguments": [
|
||||
"/Users/manager/.local/bin/g++",
|
||||
"-c",
|
||||
"-Wall",
|
||||
"-O2",
|
||||
"-std=c++2a",
|
||||
"-Iinclude",
|
||||
"-o",
|
||||
"build/val/validator",
|
||||
"validator/validator.cpp"
|
||||
],
|
||||
"directory": "/Users/manager/Documents/Research/Algorithm/BSB",
|
||||
"file": "/Users/manager/Documents/Research/Algorithm/BSB/validator/validator.cpp",
|
||||
"output": "/Users/manager/Documents/Research/Algorithm/BSB/build/val/validator"
|
||||
}
|
||||
]
|
||||
50
generator/gen1.cpp
Normal file
50
generator/gen1.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "testlib.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
using ll = unsigned long long;
|
||||
using pll = pair<ll, ll>;
|
||||
|
||||
const double eps = 1e-3;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
registerGen(argc, argv, 1);
|
||||
|
||||
ll n = opt<ll>("N");
|
||||
ll m = opt<ll>("M");
|
||||
|
||||
println(n, m);
|
||||
|
||||
vector<ll> cnt(n + 1, 0);
|
||||
for (ll i = 0; i < m; ++i) {
|
||||
ll s = rnd.next(1uLL, n);
|
||||
cnt[s]++;
|
||||
}
|
||||
|
||||
unordered_map<ll, ll> selected;
|
||||
|
||||
for (ll s = 1; s <= n; ++s) {
|
||||
ll k = cnt[s];
|
||||
if (k == 0) continue;
|
||||
|
||||
selected.clear();
|
||||
|
||||
for (ll i = 0; i < k; ++i) {
|
||||
ll range_size = (n - 1) - i;
|
||||
ll j = rnd.next(1uLL, range_size);
|
||||
|
||||
ll val_j = selected.count(j) ? selected[j] : j;
|
||||
ll val_last =
|
||||
selected.count(range_size) ? selected[range_size] : range_size;
|
||||
|
||||
ll e = (val_j < s) ? val_j : val_j + 1;
|
||||
double len = rnd.next(eps, 1.0 / eps);
|
||||
|
||||
println(s, e, len);
|
||||
|
||||
selected[j] = val_last;
|
||||
}
|
||||
}
|
||||
}
|
||||
80
generator/gen2.cpp
Normal file
80
generator/gen2.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
|
||||
#include "testlib.h"
|
||||
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
using ll = unsigned long long;
|
||||
using pll = pair<ll, ll>;
|
||||
|
||||
const double eps = 1e-3;
|
||||
|
||||
struct EdgeData {
|
||||
ll s, e;
|
||||
double len;
|
||||
};
|
||||
|
||||
void generate_edges(int thread_id, unsigned int seed, ll n, ll count,
|
||||
vector<EdgeData> &output) {
|
||||
random_t thread_rnd;
|
||||
thread_rnd.setSeed(seed);
|
||||
|
||||
output.reserve(count);
|
||||
|
||||
for (ll i = 0; i < count; ++i) {
|
||||
ll s = thread_rnd.next(1uLL, n);
|
||||
ll e = thread_rnd.next(1uLL, n);
|
||||
double len = thread_rnd.next(eps, 1.0 / eps);
|
||||
output.push_back({s, e, len});
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
registerGen(argc, argv, 1);
|
||||
|
||||
ll n = opt<ll>("N");
|
||||
double pm = opt<double>("pm");
|
||||
|
||||
ensuref(0 <= pm && pm <= 1, "pm must be in [0, 1]: %lf", pm);
|
||||
ll m = n * (n - 1) * pm;
|
||||
|
||||
unsigned int n_threads = thread::hardware_concurrency();
|
||||
if (n_threads == 0) n_threads = 2;
|
||||
|
||||
vector<unsigned int> seeds(n_threads);
|
||||
for (unsigned int i = 0; i < n_threads; ++i) {
|
||||
seeds[i] = rnd.next();
|
||||
}
|
||||
|
||||
vector<thread> threads;
|
||||
vector<vector<EdgeData>> thread_outputs(n_threads);
|
||||
ll edges_per_thread = (m + n_threads - 1) / n_threads;
|
||||
|
||||
for (unsigned int i = 0; i < n_threads; ++i) {
|
||||
threads.emplace_back(generate_edges, i, seeds[i], n, edges_per_thread,
|
||||
ref(thread_outputs[i]));
|
||||
}
|
||||
|
||||
map<pll, double> edges;
|
||||
for (unsigned int i = 0; i < n_threads; ++i) {
|
||||
threads[i].join();
|
||||
|
||||
for (const auto &data : thread_outputs[i]) {
|
||||
if (edges.size() >= m) break;
|
||||
if (data.s == data.e) continue;
|
||||
if (edges.count({data.s, data.e})) continue;
|
||||
edges[{data.s, data.e}] = data.len;
|
||||
}
|
||||
}
|
||||
|
||||
vector<pair<pll, double>> E;
|
||||
for (auto [p, l] : edges) E.push_back({p, l});
|
||||
shuffle(E.begin(), E.end());
|
||||
|
||||
println(n, m);
|
||||
for (auto [p, l] : E) println(p.first, p.second, l);
|
||||
}
|
||||
75
generator/gen3.cpp
Normal file
75
generator/gen3.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "testlib.h"
|
||||
|
||||
#include <limits>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
using ll = unsigned long long;
|
||||
using pll = pair<ll, ll>;
|
||||
|
||||
const double eps = 1e-3;
|
||||
|
||||
void generate_edges(int thread_id, unsigned int seed, ll n, double pm,
|
||||
ll start_node, ll end_node,
|
||||
vector<pair<pll, double>> &output) {
|
||||
random_t thread_rnd;
|
||||
thread_rnd.setSeed(seed);
|
||||
|
||||
for (ll s = start_node; s <= end_node; ++s) {
|
||||
for (ll e = 1; e <= n; ++e) {
|
||||
if (s == e) continue;
|
||||
|
||||
if (thread_rnd.next(1.0) < pm) {
|
||||
double len = thread_rnd.next(eps, 1.0 / eps);
|
||||
output.push_back({{s, e}, len});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
registerGen(argc, argv, 1);
|
||||
|
||||
ll n = opt<ll>("N");
|
||||
double pm = opt<double>("pm");
|
||||
ensuref(0 <= pm && pm <= 1, "pm must be in [0, 1]: %lf", pm);
|
||||
|
||||
// ll m_approx = n * (n - 1) * pm;
|
||||
|
||||
unsigned int n_threads = thread::hardware_concurrency();
|
||||
if (n_threads == 0) n_threads = 2;
|
||||
|
||||
vector<unsigned int> seeds(n_threads);
|
||||
for (unsigned int i = 0; i < n_threads; ++i) {
|
||||
seeds[i] = rnd.next(numeric_limits<unsigned int>::min(),
|
||||
numeric_limits<unsigned int>::max());
|
||||
}
|
||||
|
||||
vector<thread> threads;
|
||||
vector<vector<pair<pll, double>>> thread_outputs(n_threads);
|
||||
|
||||
ll nodes_per_thread = (n + n_threads - 1) / n_threads;
|
||||
for (unsigned int i = 0; i < n_threads; ++i) {
|
||||
ll start_node = i * nodes_per_thread + 1;
|
||||
ll end_node = min((i + 1) * nodes_per_thread, n);
|
||||
|
||||
if (start_node > end_node) continue;
|
||||
|
||||
threads.emplace_back(generate_edges, i, seeds[i], n, pm, start_node,
|
||||
end_node, ref(thread_outputs[i]));
|
||||
}
|
||||
|
||||
vector<pair<pll, double>> E;
|
||||
for (unsigned int i = 0; i < threads.size(); ++i) {
|
||||
threads[i].join();
|
||||
|
||||
E.insert(E.end(), thread_outputs[i].begin(), thread_outputs[i].end());
|
||||
}
|
||||
|
||||
shuffle(E.begin(), E.end());
|
||||
|
||||
println(n, E.size());
|
||||
for (auto [p, l] : E) println(p.first, p.second, l);
|
||||
}
|
||||
97
generator/gen4.cpp
Normal file
97
generator/gen4.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "testlib.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <thread>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
using ll = unsigned long long;
|
||||
using pll = pair<ll, ll>;
|
||||
|
||||
const double eps = 1e-3;
|
||||
|
||||
void generate_edges_parallel(ll s_start, ll s_end, ll n, const vector<ll> &cnt,
|
||||
unsigned int thread_seed,
|
||||
vector<tuple<ll, ll, double>> &buffer) {
|
||||
random_t thread_rnd;
|
||||
thread_rnd.setSeed(thread_seed);
|
||||
|
||||
unordered_map<ll, ll> selected;
|
||||
|
||||
for (ll s = s_start; s < s_end; ++s) {
|
||||
ll k = cnt[s];
|
||||
if (k == 0) continue;
|
||||
|
||||
selected.clear();
|
||||
|
||||
for (ll i = 0; i < k; ++i) {
|
||||
ll range_size = (n - 1) - i;
|
||||
ll j = thread_rnd.next(1uLL, range_size);
|
||||
|
||||
ll val_j = selected.count(j) ? selected[j] : j;
|
||||
ll val_last =
|
||||
selected.count(range_size) ? selected[range_size] : range_size;
|
||||
|
||||
ll e = (val_j < s) ? val_j : val_j + 1;
|
||||
double len = thread_rnd.next(eps, 1.0 / eps);
|
||||
|
||||
buffer.emplace_back(s, e, len);
|
||||
|
||||
selected[j] = val_last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// 메인 RNG 초기화
|
||||
registerGen(argc, argv, 1);
|
||||
|
||||
ll n = opt<ll>("N");
|
||||
ll m = opt<ll>("M");
|
||||
|
||||
println(n, m);
|
||||
|
||||
vector<ll> cnt(n + 1, 0);
|
||||
for (ll i = 0; i < m; ++i) {
|
||||
ll s = rnd.next(1uLL, n);
|
||||
cnt[s]++;
|
||||
}
|
||||
|
||||
const int num_threads = thread::hardware_concurrency();
|
||||
vector<thread> threads;
|
||||
|
||||
vector<unsigned int> thread_seeds;
|
||||
vector<vector<tuple<ll, ll, double>>> thread_buffers(num_threads);
|
||||
|
||||
for (int i = 0; i < num_threads; ++i) {
|
||||
thread_seeds.push_back(rnd.next(1u, 1000000u));
|
||||
}
|
||||
|
||||
ll s_batch_size = (n + num_threads) / num_threads;
|
||||
ll s_current = 1;
|
||||
|
||||
for (int i = 0; i < num_threads; ++i) {
|
||||
ll s_start = s_current;
|
||||
ll s_end = min(s_start + s_batch_size, n + 1);
|
||||
if (s_start >= s_end) break;
|
||||
|
||||
threads.emplace_back(generate_edges_parallel, s_start, s_end, n,
|
||||
ref(cnt), thread_seeds[i], ref(thread_buffers[i]));
|
||||
|
||||
s_current = s_end;
|
||||
}
|
||||
|
||||
for (auto &t : threads) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
cout << fixed << setprecision(15);
|
||||
for (int i = 0; i < num_threads; ++i) {
|
||||
for (const auto &edge : thread_buffers[i]) {
|
||||
println(get<0>(edge), get<1>(edge), get<2>(edge));
|
||||
}
|
||||
}
|
||||
}
|
||||
6511
include/testlib.h
Normal file
6511
include/testlib.h
Normal file
File diff suppressed because it is too large
Load Diff
51
src/bsb/main.cpp
Normal file
51
src/bsb/main.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
|
||||
const double INF = numeric_limits<double>::infinity();
|
||||
|
||||
int main() {
|
||||
std::ios::sync_with_stdio(false);
|
||||
|
||||
ll n, m;
|
||||
cin >> n >> m;
|
||||
|
||||
vector<vector<pair<int, double> > > adj(n + 1);
|
||||
|
||||
for (ll i = 1; i <= m; i++) {
|
||||
ll s, e;
|
||||
double len;
|
||||
cin >> s >> e >> len;
|
||||
|
||||
adj[s].emplace_back(e, len);
|
||||
}
|
||||
|
||||
vector<double> dist(n + 1, INF);
|
||||
|
||||
using Item = pair<double, ll>;
|
||||
priority_queue<Item, vector<Item>, greater<Item> > pq;
|
||||
vector<bool> chk(n + 1);
|
||||
|
||||
dist[1] = 0;
|
||||
pq.push({dist[1], 1});
|
||||
while (!pq.empty()) {
|
||||
auto [_, s] = pq.top();
|
||||
pq.pop();
|
||||
if (chk[s]) continue;
|
||||
chk[s] = true;
|
||||
for (auto [i, len] : adj[s]) {
|
||||
if (dist[i] > dist[s] + len) {
|
||||
dist[i] = dist[s] + len;
|
||||
pq.push({dist[i], i});
|
||||
}
|
||||
}
|
||||
}
|
||||
cout << fixed << setprecision(15);
|
||||
for (ll i = 1; i <= n; i++) cout << dist[i] << '\n';
|
||||
}
|
||||
50
src/dijk/main.cpp
Normal file
50
src/dijk/main.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
|
||||
const double INF = numeric_limits<double>::infinity();
|
||||
|
||||
int main() {
|
||||
std::ios::sync_with_stdio(false);
|
||||
|
||||
ll n, m;
|
||||
cin >> n >> m;
|
||||
|
||||
vector<vector<pair<int, double> > > adj(n + 1);
|
||||
|
||||
for (ll i = 1; i <= m; i++) {
|
||||
ll s, e;
|
||||
double len;
|
||||
cin >> s >> e >> len;
|
||||
|
||||
adj[s].emplace_back(e, len);
|
||||
}
|
||||
|
||||
vector<double> dist(n + 1, INF);
|
||||
|
||||
using Item = pair<double, ll>;
|
||||
priority_queue<Item, vector<Item>, greater<Item> > pq;
|
||||
vector<bool> chk(n + 1);
|
||||
|
||||
dist[1] = 0;
|
||||
pq.push({dist[1], 1});
|
||||
while (!pq.empty()) {
|
||||
auto [_, s] = pq.top();
|
||||
pq.pop();
|
||||
if (chk[s]) continue;
|
||||
chk[s] = true;
|
||||
for (auto [i, len] : adj[s]) {
|
||||
if (dist[i] > dist[s] + len) {
|
||||
dist[i] = dist[s] + len;
|
||||
pq.push({dist[i], i});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ll i = 1; i <= n; i++) cout << dist[i] << '\n';
|
||||
}
|
||||
38
validator/validator.cpp
Normal file
38
validator/validator.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "testlib.h"
|
||||
|
||||
using namespace std;
|
||||
using ll = long long;
|
||||
|
||||
const int MX = 1e9;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
registerValidation(argc, argv);
|
||||
|
||||
ll n = inf.readLong(1LL, MX, "N");
|
||||
inf.readSpace();
|
||||
ll m = inf.readLong(0, n * (n - 1), "M");
|
||||
inf.readEoln();
|
||||
|
||||
set<pair<int, int> > edges;
|
||||
for (ll i = 1; i <= m; i++) {
|
||||
ll s, e;
|
||||
double len;
|
||||
s = inf.readLong(1LL, n);
|
||||
inf.readSpace();
|
||||
e = inf.readLong(1LL, n);
|
||||
inf.readSpace();
|
||||
len = inf.readDouble();
|
||||
inf.readEoln();
|
||||
|
||||
ensuref(s != e, "s must not be equal to e: edge: %lld -> %lld", s, e);
|
||||
ensuref(len >= 0,
|
||||
"len must be greater than or equal to zero: %lld->%lld, %lf", s,
|
||||
e, len);
|
||||
|
||||
ensuref(!edges.contains({s, e}),
|
||||
"Edges must be unique: multiple edge %lld -> %lld", s, e);
|
||||
|
||||
edges.emplace(s, e);
|
||||
}
|
||||
inf.readEof();
|
||||
}
|
||||
Reference in New Issue
Block a user