mirror of
https://gitcode.com/Zengtudor/alg2025.git
synced 2025-09-18 13:51:15 +00:00
Compare commits
No commits in common. "b7d76322ab4edbd0effbd5cc1d8b527efd782c38" and "a1024cfc8e8b7ff5177c684a2803c7473b39405d" have entirely different histories.
b7d76322ab
...
a1024cfc8e
6
src/8/12/P8865.cpp
Normal file
6
src/8/12/P8865.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
|
||||||
|
}
|
@ -1,102 +0,0 @@
|
|||||||
#include <cstdint>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <iostream>
|
|
||||||
#include <istream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
using ll = int64_t;
|
|
||||||
const ll mod = 998244353;
|
|
||||||
|
|
||||||
#define p(v)do{\
|
|
||||||
std::cout<<#v<<":\n";\
|
|
||||||
for(ll i=1;i<=n;i++){\
|
|
||||||
for(ll j=1;j<=m;j++){\
|
|
||||||
std::cout<<(v)[i][j]<<' ';\
|
|
||||||
}\
|
|
||||||
std::cout<<"\n";\
|
|
||||||
}\
|
|
||||||
}while(0)
|
|
||||||
|
|
||||||
int main(){
|
|
||||||
std::iostream::sync_with_stdio(false);
|
|
||||||
std::cin.tie(nullptr);
|
|
||||||
|
|
||||||
ll t,id;
|
|
||||||
std::cin>>t>>id;
|
|
||||||
while(t--){
|
|
||||||
ll n,m,c,f;
|
|
||||||
std::cin>>n>>m>>c>>f;
|
|
||||||
static std::vector<std::vector<bool>> map;
|
|
||||||
map.clear();
|
|
||||||
map.resize(n+1,std::vector<bool>(m+1));
|
|
||||||
for(ll i=1;i<=n;i++){
|
|
||||||
static std::string s;
|
|
||||||
std::cin>>s;
|
|
||||||
ll idx=1;
|
|
||||||
for(char c:s){
|
|
||||||
map[i][idx++]=c-'0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<std::vector<ll>> rt;
|
|
||||||
rt.clear();
|
|
||||||
rt.resize(n+1,std::vector<ll>(m+2));
|
|
||||||
for(ll i=1;i<=n;i++){
|
|
||||||
for(ll j=m;j>=1;j--){
|
|
||||||
if(map[i][j]==0){
|
|
||||||
rt[i][j]=(rt[i][j+1]+1)%mod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// p(rt);
|
|
||||||
static std::vector<std::vector<ll>> d;
|
|
||||||
d.clear();
|
|
||||||
d.resize(n+2,std::vector<ll>(m+1));
|
|
||||||
for(ll j=1;j<=m;j++){
|
|
||||||
for(ll i=n;i>=1;i--){
|
|
||||||
if(map[i][j]==0){
|
|
||||||
d[i][j]=(d[i+1][j]+1)%mod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// p(d);
|
|
||||||
ll ansc=0,ansf=0;
|
|
||||||
static std::vector<std::vector<ll>> visc,visf;
|
|
||||||
visc.clear();visc.resize(n+1,std::vector<ll>(m+1));
|
|
||||||
visf.clear();visf.resize(n+1,std::vector<ll>(m+1));
|
|
||||||
for(ll i=1;i<=n-2;i++){
|
|
||||||
for(ll j=1;j<=m;j++){
|
|
||||||
if(rt[i][j]<=1 || rt[i+1][j]==0 || rt[i+2][j]==0){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ll top = rt[i][j]-1;
|
|
||||||
// ll nansc = 0;
|
|
||||||
// ll nansf = 0;
|
|
||||||
ll bc=ansc,bf=ansf;
|
|
||||||
for(ll k=i+2;k<=n;k++){
|
|
||||||
if(rt[k][j]==0)break;
|
|
||||||
if(rt[k][j]>1){
|
|
||||||
// if(visc[i][j]){
|
|
||||||
// ansc=(ansc+visc[i][j])%mod;
|
|
||||||
// }else{
|
|
||||||
ansc=(ansc+top*(rt[k][j]-1)%mod)%mod;
|
|
||||||
visc[i][j]=((ansc-bc)%mod+mod)%mod;
|
|
||||||
// }
|
|
||||||
// if(visf[i][j]){
|
|
||||||
// ansf=(ansf+visf[i][j])%mod;
|
|
||||||
// }else{
|
|
||||||
ansf=(ansf+top*(rt[k][j]-1)%mod*(d[k][j]-1)%mod)%mod;
|
|
||||||
visf[i][j]=((ansf-bf)%mod+mod)%mod;
|
|
||||||
// }
|
|
||||||
// printf("C format i=%lld, j=%lld, k=%lld, nowc=%lld\n"
|
|
||||||
// ,i,j,k, ansc+=top*(rt[k][j]-1));
|
|
||||||
// printf("F format i=%lld, j=%lld, k=%lld, nowf=%lld\n"
|
|
||||||
// ,i,j,k, ansf+= top*(rt[k][j]-1)*(d[k][j]-1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cout<<ansc*c%mod<<" "<<ansf*f%mod<<"\n";
|
|
||||||
}
|
|
||||||
}
|
|
244
src/test.cpp
244
src/test.cpp
@ -1,247 +1,3 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <random>
|
|
||||||
#include <queue>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
// --- 常量定义 ---
|
|
||||||
// 使用 enum class 增强类型安全和代码可读性
|
|
||||||
enum class TileType : char {
|
|
||||||
WALL = '#',
|
|
||||||
FLOOR = '.',
|
|
||||||
HOUSE_SPACE = 'H', // 临时标记,最终会变回 FLOOR
|
|
||||||
EXTERIOR = ' ' // 临时标记,用于洪水填充
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- 辅助结构体:矩形房间 ---
|
|
||||||
struct Rect {
|
|
||||||
int x, y, w, h;
|
|
||||||
|
|
||||||
// 检查此矩形是否与另一个矩形相交(包括边缘接触)
|
|
||||||
bool intersects(const Rect& other) const {
|
|
||||||
return (x < other.x + other.w && x + w > other.x &&
|
|
||||||
y < other.y + other.h && y + h > other.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取中心点坐标
|
|
||||||
std::pair<int, int> center() const {
|
|
||||||
return {x + w / 2, y + h / 2};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- 地图生成器类 ---
|
|
||||||
class MapGenerator {
|
|
||||||
public:
|
|
||||||
MapGenerator(int width, int height)
|
|
||||||
: width_(width), height_(height),
|
|
||||||
// 使用 std::random_device 获取真随机数种子,初始化梅森旋转算法
|
|
||||||
rng_(std::random_device{}()) {
|
|
||||||
if (width_ <= 0 || height_ <= 0) {
|
|
||||||
throw std::invalid_argument("Map dimensions must be positive.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 主生成函数
|
|
||||||
void generate(int max_rooms, int min_room_size, int max_room_size) {
|
|
||||||
// 1. 初始化地图,全部填充为墙壁
|
|
||||||
initializeMap();
|
|
||||||
|
|
||||||
// 2. 随机放置房间
|
|
||||||
createRooms(max_rooms, min_room_size, max_room_size);
|
|
||||||
|
|
||||||
// 3. 按顺序连接所有房间
|
|
||||||
createCorridors();
|
|
||||||
|
|
||||||
// 4. 识别并填充“房屋空间”
|
|
||||||
identifyAndFillHouseSpaces();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打印地图到控制台
|
|
||||||
void printMap() const {
|
|
||||||
for (int y = 0; y < height_; ++y) {
|
|
||||||
for (int x = 0; x < width_; ++x) {
|
|
||||||
std::cout << static_cast<char>(map_[y][x]);
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int width_, height_;
|
|
||||||
std::vector<std::vector<TileType>> map_;
|
|
||||||
std::vector<Rect> rooms_;
|
|
||||||
std::mt19937 rng_; // 高质量随机数生成器
|
|
||||||
|
|
||||||
// 步骤1: 初始化地图,全部设置为墙壁
|
|
||||||
void initializeMap() {
|
|
||||||
map_.assign(height_, std::vector<TileType>(width_, TileType::WALL));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 步骤2: 创造不重叠的房间
|
|
||||||
void createRooms(int max_rooms, int min_room_size, int max_room_size) {
|
|
||||||
rooms_.clear();
|
|
||||||
std::uniform_int_distribution<> size_dist(min_room_size, max_room_size);
|
|
||||||
std::uniform_int_distribution<> x_dist(1, width_ - max_room_size - 1);
|
|
||||||
std::uniform_int_distribution<> y_dist(1, height_ - max_room_size - 1);
|
|
||||||
|
|
||||||
// 尝试放置 max_rooms 个房间
|
|
||||||
for (int i = 0; i < max_rooms; ++i) {
|
|
||||||
Rect new_room;
|
|
||||||
new_room.w = size_dist(rng_);
|
|
||||||
new_room.h = size_dist(rng_);
|
|
||||||
new_room.x = x_dist(rng_);
|
|
||||||
new_room.y = y_dist(rng_);
|
|
||||||
|
|
||||||
// 确保房间在地图边界内
|
|
||||||
if (new_room.x + new_room.w >= width_ - 1 || new_room.y + new_room.h >= height_ - 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查新房间是否与已存在的房间重叠
|
|
||||||
bool overlaps = false;
|
|
||||||
for (const auto& room : rooms_) {
|
|
||||||
if (new_room.intersects(room)) {
|
|
||||||
overlaps = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!overlaps) {
|
|
||||||
carveRoom(new_room);
|
|
||||||
rooms_.push_back(new_room);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在地图上“挖掘”一个房间
|
|
||||||
void carveRoom(const Rect& room) {
|
|
||||||
for (int y = room.y; y < room.y + room.h; ++y) {
|
|
||||||
for (int x = room.x; x < room.x + room.w; ++x) {
|
|
||||||
map_[y][x] = TileType::FLOOR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 步骤3: 连接房间
|
|
||||||
void createCorridors() {
|
|
||||||
if (rooms_.size() < 2) return;
|
|
||||||
// 按房间位置排序,以连接邻近的房间
|
|
||||||
std::sort(rooms_.begin(), rooms_.end(), [](const Rect& a, const Rect& b){
|
|
||||||
return (a.x + a.y) < (b.x + b.y);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (size_t i = 0; i < rooms_.size() - 1; ++i) {
|
|
||||||
auto [x1, y1] = rooms_[i].center();
|
|
||||||
auto [x2, y2] = rooms_[i+1].center();
|
|
||||||
carvePath(x1, y1, x2, y2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 挖掘一条 L 形路径连接两个点
|
|
||||||
void carvePath(int x1, int y1, int x2, int y2) {
|
|
||||||
// 随机决定先水平挖还是先垂直挖
|
|
||||||
if (std::uniform_int_distribution<>(0, 1)(rng_) == 0) {
|
|
||||||
carveHorizontalTunnel(x1, x2, y1);
|
|
||||||
carveVerticalTunnel(y1, y2, x2);
|
|
||||||
} else {
|
|
||||||
carveVerticalTunnel(y1, y2, x1);
|
|
||||||
carveHorizontalTunnel(x1, x2, y2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void carveHorizontalTunnel(int x1, int x2, int y) {
|
|
||||||
for (int x = std::min(x1, x2); x <= std::max(x1, x2); ++x) {
|
|
||||||
map_[y][x] = TileType::FLOOR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void carveVerticalTunnel(int y1, int y2, int x) {
|
|
||||||
for (int y = std::min(y1, y2); y <= std::max(y1, y2); ++y) {
|
|
||||||
map_[y][x] = TileType::FLOOR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 步骤4: 关键步骤 - 识别并填充房屋空间
|
|
||||||
void identifyAndFillHouseSpaces() {
|
|
||||||
// 使用洪水填充算法(BFS)标记所有外部空间
|
|
||||||
// 从 (0,0) 开始,所有能到达的墙壁都被认为是外部的一部分
|
|
||||||
std::queue<std::pair<int, int>> q;
|
|
||||||
q.push({0, 0});
|
|
||||||
|
|
||||||
// 创建一个访问记录数组,防止重复处理
|
|
||||||
std::vector<std::vector<bool>> visited(height_, std::vector<bool>(width_, false));
|
|
||||||
visited[0][0] = true;
|
|
||||||
map_[0][0] = TileType::EXTERIOR; // 标记为外部
|
|
||||||
|
|
||||||
// 定义 4 个移动方向
|
|
||||||
int dx[] = {0, 0, 1, -1};
|
|
||||||
int dy[] = {1, -1, 0, 0};
|
|
||||||
|
|
||||||
while (!q.empty()) {
|
|
||||||
auto [cx, cy] = q.front();
|
|
||||||
q.pop();
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
|
||||||
int nx = cx + dx[i];
|
|
||||||
int ny = cy + dy[i];
|
|
||||||
|
|
||||||
// 检查边界
|
|
||||||
if (nx < 0 || ny < 0 || nx >= width_ || ny >= height_) continue;
|
|
||||||
|
|
||||||
// 如果邻居是墙壁且未被访问,则将其标记为外部并加入队列
|
|
||||||
if (!visited[ny][nx] && map_[ny][nx] == TileType::WALL) {
|
|
||||||
visited[ny][nx] = true;
|
|
||||||
map_[ny][nx] = TileType::EXTERIOR;
|
|
||||||
q.push({nx, ny});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遍历整个地图,将在上一步中未被标记为 EXTERIOR 的所有 WALL 包围的区域,
|
|
||||||
// 即原始的 FLOOR 区域,识别为 HOUSE_SPACE。
|
|
||||||
// 但根据您的要求,房屋空间也用空地表示,所以我们只需把 EXTERIOR 变回 WALL,
|
|
||||||
// 把未被触及的 WALL 留作围墙,而所有 FLOOR 区域自然就是我们想要的。
|
|
||||||
// 这一步之后,我们实际上已经区分了 "内部墙" 和 "外部墙"。
|
|
||||||
|
|
||||||
// 最终清理:将临时标记转换回最终的瓦片类型
|
|
||||||
for (int y = 0; y < height_; ++y) {
|
|
||||||
for (int x = 0; x < width_; ++x) {
|
|
||||||
if (map_[y][x] == TileType::EXTERIOR) {
|
|
||||||
map_[y][x] = TileType::WALL; // 将外部标记恢复为墙
|
|
||||||
}
|
|
||||||
// 所有原本是 FLOOR 的地方,现在可以被理解为 房屋空间 或 走廊,
|
|
||||||
// 并且都用 '.' 表示,完美符合要求。
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- 主函数 ---
|
|
||||||
int main(){
|
int main(){
|
||||||
// 设置地图参数
|
|
||||||
const int MAP_WIDTH = 80;
|
|
||||||
const int MAP_HEIGHT = 40;
|
|
||||||
const int MAX_ROOMS = 15;
|
|
||||||
const int MIN_ROOM_SIZE = 5;
|
|
||||||
const int MAX_ROOM_SIZE = 10;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 创建生成器实例
|
|
||||||
MapGenerator generator(MAP_WIDTH, MAP_HEIGHT);
|
|
||||||
|
|
||||||
// 生成地图
|
|
||||||
generator.generate(MAX_ROOMS, MIN_ROOM_SIZE, MAX_ROOM_SIZE);
|
|
||||||
|
|
||||||
// 打印结果
|
|
||||||
std::cout << "--- Generated Map ---" << std::endl;
|
|
||||||
std::cout << "#: Wall, .: Floor/House Space" << std::endl;
|
|
||||||
generator.printMap();
|
|
||||||
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
std::cerr << "Error: " << e.what() << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user