Google Grad Test Second Round

本文解析了四道编程挑战题目:SudokuChecker验证数独的有效性,DragonMaze求解迷宫最大收益,IgnoreAllMyComments处理特殊注释,Hex分析游戏状态。通过详细阐述算法思路与实现细节,为读者提供了宝贵的解题思路。

Problem A Sudoku Checker

总结: 简单模拟题. 时间复杂度 o(n^4)

#include <iostream>

#include <stdio.h>

#include <memory.h>

#include <algorithm>

#include <vector>

#include <map>

#include <set>

#include <string>

#include <deque>

#define MIN(x,y) (x)<(y)?(x):(y)

using namespace std;

 

bool valid;

int matrix[1600][1600];

 

 

void initSet(set<int> &set_it, int n) {

    

    for(int i = 1; i <= n*n; i++)

        set_it.insert(i);

}

 

void smallPart(int x, int y, int n) {

    set<int> tmp;

    initSet(tmp, n);

    

    for(int i = x; i < n; i ++) {

        for(int j = y; j < n; j ++) {

            if(tmp.count(matrix[i][j]) == 0) {

                valid = false;

                return;

            }

            tmp.erase(tmp.find(matrix[i][j]));

        }

    }

}

 

void bigPart(int n) {

    for(int i = 0; i < n*n && valid; i ++) { /* for each line */

        set<int> tmp;

        initSet(tmp, n);

        for(int j = 0; j < n*n && valid; j ++) {

            if(tmp.count(matrix[i][j]) == 0) {

                valid = false;

                return;

            }

            tmp.erase(tmp.find(matrix[i][j]));

        }

    }

 

    for(int j = 0; j < n*n && valid; j ++) {

        set<int> tmp;

        initSet(tmp, n);

        for(int i = 0; i < n*n && valid; i ++) {

            if(tmp.count(matrix[i][j]) == 0) {

                valid = false;

                return;

            }

            tmp.erase(tmp.find(matrix[i][j]));

        }

    }

 

    for(int t = 0; t < n*n; t ++) {

        int i = t / n;

        int j = t % n;

 

        smallPart(i*n, j*n, n);

    }

}

 

int main() {

    freopen("C:\\Users\\vincent\\Dropbox\\workplacce\\joj\\test.txt", "r", stdin);

    

    int T, iCase = 0;

    scanf("%d", &T);

 

    while(T --) {

        valid = true;

        int n;

        scanf("%d", &n);

 

        for(int i = 0; i < n*n; i ++) {

            for(int j = 0; j < n*n; j ++) {

                scanf("%d", &matrix[i][j]);

            }

        }

        bigPart(n);

 

        if(valid) {

            printf("Case #%d: Yes\n", iCase);

        }else {

            printf("Case #%d: No\n", iCase);

        }

    }

 

    return 0;

}

 

Problem B Dragon Maze

思路:

1. 单源点最短路径变形题. 我用到了两个数组分别判断一个点是否已经被加入到队列中, 和是否还能够被更新该点获得的最大价值, 我觉得这是有些低效的, 应当有更优雅的解法

#include <iostream>

#include <stdio.h>

#include <memory.h>

#include <algorithm>

#include <vector>

#include <map>

#include <set>

#include <string>

#include <deque>

#define MIN(x,y) (x)<(y)?(x):(y)

using namespace std;

 

int value[200][200];

bool visited[200][200];

bool added[200][200];

int matrix[200][200];

 

int dir[4][2] = {0,1, 1,0, 0,-1, -1,0}; /* */

const int INF = 0X3F3F3F3F;

 

int sx, sy, ex, ey;

int n, m;

 

 

/* using more space for simplicity */

class Node {

public:

    int x, y, dist;

    Node() {

        x = y = dist = 0;

    }

    Node(int _x, int _y, int _dist):x(_x), y(_y), dist(_dist) {}

};

 

int bfs() {

    deque<Node> queue;

    int minDist = INF;

 

    memset(visited, 0, sizeof(visited));

    memset(value, 0, sizeof(value));

    memset(added, 0, sizeof(added));

 

    queue.push_back(Node(sx, sy, 0));

    added[sx][sy] = 1;

    value[sx][sy] = matrix[sx][sy];

 

    while(!queue.empty()) {

        Node fath = queue.front();

        queue.pop_front();

        visited[fath.x][fath.y] = 1;

        

        if(fath.x == ex && fath.y == ey) { /* give same level nodes opportunity*/

            minDist = fath.dist;

        }

 

        if(fath.dist > minDist) {

            break;

        }

 

        for(int i = 0; i < 4; i ++) {

            int cx = fath.x + dir[i][0];

            int cy = fath.y + dir[i][1];

 

            if(cx < 0 || cy < 0 || cx > n-1 || cy > m-1)

                continue;

 

            if(matrix[cx][cy] < 0) { /* dangerous place */

                continue;

            }

 

            if(!visited[cx][cy]) { /* update */

                value[cx][cy] = max(value[cx][cy], value[fath.x][fath.y]+matrix[cx][cy]);    

                if(!added[cx][cy]) {

                    queue.push_back(Node(cx, cy, fath.dist+1));

                    added[cx][cy] = 1;

                }

            }

        }

    }

 

    return value[ex][ey];

}

 

int main() {

    freopen("C:\\Users\\vincent\\Dropbox\\workplacce\\joj\\test.txt", "r", stdin);

 

    int T, iCase = 0;

    scanf("%d", &T);

    

    while(T --) {

        scanf("%d%d", &n, &m);

        scanf("%d%d%d%d", &sx, &sy, &ex, &ey);

        iCase ++;

 

        for(int i = 0; i < n; i ++) {

            for(int j = 0; j < m; j ++) {

                scanf("%d", &matrix[i][j]);

            }

        }

 

        int res = bfs();

        printf("Case #%d: ", iCase);

        if(res == 0) {

            printf("Mission Impossible\n");

        }else {

            printf("%d\n", res);

        }

    }

 

    return 0;

}

 

Problem E Ignore All My Comments

思路:

1. 每次读取一行, 并且把每次读取的字符放到 string , 100kb 装的下

2. 查找符号 '/', 以此为根据向右扩展得到 /*, 向左扩展得到 */, 能使问题简化

3. 我最初用 scanf() 来移位, 结局只能说太惨了, 因为没有 look_back() 功能, //* 这种类型的就判断不出了

 

Problem C Hex

思路

1. 所有不正确的状态: a. 双方棋子相差 1 以上; b. 红方赢, 但蓝方的棋子更多. c. 红方赢, 但红方的棋子路径上没有关键点.

2. 这道题是相当难得, 师兄当初靠抱 ACMer 的大腿才弄过去

 

Problem B Meet and Party

1. 最简单的解法是枚举, 但只能过小数据.

2. 优化, 每次计算一个点到一块区域的长度之和.

3. 最优解法

转载于:https://www.cnblogs.com/zhouzhuo/p/3660768.html

出现问题迭代 1 | 总损失: 6.72196 | 距离损失: 10.1859 | 面积损失: 0.288881 0x00007FFE5A118508 (torch_cpu.dll)处(位于 test.exe 中)引发的异常: 0xC000008E: Floating-point division by zero (参数: 0x0000000000000000, 0x0000000000001924)。 “test.exe”(Win32): 已加载“C:\Windows\System32\duser.dll”。 “test.exe”(Win32): 已加载“C:\Windows\System32\xmllite.dll”。 “test.exe”(Win32): 已加载“C:\Windows\System32\atlthunk.dll”。 “test.exe”(Win32): 已卸载“C:\Windows\System32\xmllite.dll” 0x00007FFF5CE8933A (KernelBase.dll)处(位于 test.exe 中)引发的异常: 0x8001010D: 因为应用程序正在发送一个输入同步呼叫,所以无法执行传出的呼叫。。 “test.exe”(Win32): 已加载“C:\Windows\System32\OneCoreCommonProxyStub.dll”。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FDF50 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 线程 33260 已退出,返回值为 0 (0x0)。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE2B0 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE300 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FDF50 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE2B0 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE300 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 线程 36532 已退出,返回值为 0 (0x0)。 线程 1208 已退出,返回值为 0 (0x0)。 线程 36320 已退出,返回值为 0 (0x0)。 线程 22984 已退出,返回值为 0 (0x0)。 线程 4384 已退出,返回值为 0 (0x0)。 线程 17576 已退出,返回值为 0 (0x0)。 线程 14288 已退出,返回值为 0 (0x0)。 线程 35492 已退出,返回值为 0 (0x0)。 线程 22860 已退出,返回值为 0 (0x0)。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE330 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE3A0 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE330 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE3A0 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE330 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: wil::ResultException,位于内存位置 0x000000EDA68FE3A0 处。 0x00007FFF5CE8933A 处(位于 test.exe 中)引发的异常: Microsoft C++ 异常: [rethrow],位于内存位置 0x0000000000000000 处。 线程 30132 已退出,返回值为 0 (0x0)。 线程 27048 已退出,返回值为 0 (0x0)。 线程 27212 已退出,返回值为 0 (0x0)。 线程 33764 已退出,返回值为 0 (0x0)。 线程 35108 已退出,返回值为 0 (0x0)。 线程 12392 已退出,返回值为 0 (0x0)。 #define PARTICLESWARMMETHOD_EXPORTS // 定义导出宏 #include "particleSwarmMethod.h" torch::Tensor distance_point_to_segment(const torch::Tensor& P, const torch::Tensor& A, const torch::Tensor& B) { auto AP = P - A; auto AB = B - A; auto ab_sq = AB.pow(2).sum(); if (ab_sq.item<float>() == 0) { return AP.norm(2, 1); } auto t = torch::mv(AP, AB.squeeze()) / ab_sq; t = torch::clamp(t, 0.0, 1.0); auto proj = A + t.unsqueeze(1) * AB; return (P - proj).norm(2, 1); } std::vector<std::vector<float>> particle(const std::vector<float>& wy, const std::vector<float>& zh) { std::vector<std::vector<float>> particles;//六边形初始化 auto wymax = *std::max_element(wy.begin(), wy.end()); auto wymin = *std::min_element(wy.begin(), wy.end()); auto zhmax = *std::max_element(zh.begin(), zh.end()); auto zhmin = *std::min_element(zh.begin(), zh.end()); particles.push_back({ wymin, zhmax }); particles.push_back({ wymax, zhmax }); particles.push_back({ wymax, (zhmax - zhmin) * 0.5f + zhmin }); particles.push_back({ (wymax - wymin) * 0.5f + wymin, (zhmax - zhmin) * 0.5f + zhmin }); particles.push_back({ (wymax - wymin) * 0.5f + wymin, zhmin }); particles.push_back({ wymin, zhmin }); return particles; } // 应用约束 torch::Tensor apply_constraints(torch::Tensor vertices) { torch::NoGradGuard no_grad; // 临时禁用梯度计算 // 边界约束 vertices.data() = torch::clamp(vertices, -0.05, 1.02); auto min_val = torch::tensor(0.2, vertices.options()); auto max_val = vertices.index({ 1, 0 }) * 1.1; vertices.index_put_({ 2, 0 }, torch::clamp(vertices.index({ 2, 0 }), min_val, max_val)); vertices.index_put_({ 2, 1 }, torch::clamp(vertices.index({ 2, 1 }), 0.2, 1.02)); vertices.index_put_({ 3, 0 }, torch::clamp(vertices.index({ 3, 0 }), vertices.index({ 4, 0 }), vertices.index({ 2, 0 }) * 1.1)); vertices.index_put_({ 3, 1 }, torch::clamp(vertices.index({ 3, 1 }), vertices.index({ 4, 1 }) * 1.1, vertices.index({ 2, 1 }))); vertices.index_put_({ 4, 0 }, torch::clamp(vertices.index({ 4, 0 }), vertices.index({ 5, 0 }) * 1.1, vertices.index({ 3, 0 }))); vertices.index_put_({ 4, 1 }, torch::clamp(vertices.index({ 4, 1 }), torch::nullopt, vertices.index({ 5, 1 }) + 0.1)); return vertices; } // 计算损失函数 std::tuple<torch::Tensor, torch::Tensor, torch::Tensor> calculate_gradient_descent_loss(const torch::Tensor& vertices, const torch::Tensor& points, const torch::Tensor& target_area, float lambda1) { // 计算六边形面积 auto shifted_vertices = torch::roll(vertices, -1, 0); auto x = vertices.index({ torch::indexing::Slice(), 0 }); auto y = vertices.index({ torch::indexing::Slice(), 1 }); auto x_shifted = shifted_vertices.index({ torch::indexing::Slice(), 0 }); auto y_shifted = shifted_vertices.index({ torch::indexing::Slice(), 1 }); auto area = 0.5 * torch::abs(torch::sum(x * y_shifted - y * x_shifted)); // 计算所有边到数据点的距离 std::vector<std::pair<int, int>> edges; for (int i = 0; i < 6; ++i) { edges.emplace_back(i, (i + 1) % 6); // 添加边 (i, (i+1)%6) } std::vector<torch::Tensor> dists; for (const auto& edge : edges) { auto A = vertices[edge.first].unsqueeze(0); // [1, 2] auto B = vertices[edge.second].unsqueeze(0); // [1, 2] auto dist = distance_point_to_segment(points, A, B); dists.push_back(dist); } auto dist_matrix = torch::stack(dists, 1); auto min_dists = std::get<0>(torch::min(dist_matrix, 1)); auto distance_loss = torch::sum(min_dists); // 计算面积损失 auto area_loss = torch::abs(area - target_area); // 总损失 auto total_loss = (1 - lambda1) * area_loss + lambda1 * distance_loss; return { total_loss, distance_loss, area_loss }; } extern "C" PARTICLESWARMMETHOD_API int* opening_closing_point_recognition( const float* wy, int wySize, const float* zh, int zhSize, int iterations, bool print1, float lambda1, int* resultSize ) { // 输出所有输入信息 std::cout << "Opening_closing_point_recognition 函数的输入信息:" << std::endl; std::cout << "wy 数组内容:"; for (int i = 0; i < wySize; ++i) { std::cout << wy[i]; if (i < wySize - 1) { std::cout << ", "; } } std::cout << std::endl; std::cout << "wy 数组大小: " << wySize << std::endl; std::cout << "zh 数组内容:"; for (int i = 0; i < zhSize; ++i) { std::cout << zh[i]; if (i < zhSize - 1) { std::cout << ", "; } } std::cout << std::endl; std::cout << "zh 数组大小: " << zhSize << std::endl; std::cout << "迭代次数: " << iterations << std::endl; std::cout << "是否打印信息: " << (print1 ? "是" : "否") << std::endl; std::cout << "权重系数 lambda1: " << lambda1 << std::endl; // 数据归一化 auto wmin = *std::min_element(wy, wy + wySize); auto wmax = *std::max_element(wy, wy + wySize); auto zmin = *std::min_element(zh, zh + zhSize); auto zmax = *std::max_element(zh, zh + zhSize); std::vector<float> wy_nored(wySize), zh_nored(zhSize); for (int i = 0; i < wySize; ++i) { wy_nored[i] = (wy[i] - wmin) / (wmax - wmin); } for (int i = 0; i < zhSize; ++i) { zh_nored[i] = (zh[i] - zmin) / (zmax - zmin); } std::vector<float> low_before = { *std::min_element(wy_nored.begin(), wy_nored.end()) - 0.1f, *std::min_element(zh_nored.begin(), zh_nored.end()) - 0.1f }; std::vector<float> up_before = { *std::max_element(wy_nored.begin(), wy_nored.end()) * 1.1f, *std::max_element(zh_nored.begin(), zh_nored.end()) * 1.1f }; std::vector<float> low, up; for (int i = 0; i < 6; ++i) { low.insert(low.end(), low_before.begin(), low_before.end()); up.insert(up.end(), up_before.begin(), up_before.end()); } // 初始化六边形 std::vector<std::vector<float>> polygon = particle(wy_nored, zh_nored); // 将 polygon (vector<vector<float>>) 转换为 Tensor std::vector<float> flattened; for (const auto& point : polygon) { flattened.insert(flattened.end(), point.begin(), point.end()); } torch::Tensor vertices = torch::tensor(flattened, torch::dtype(torch::kFloat32)) .view({ -1, 2 }) .requires_grad_(true); // 创建优化器 auto optimizer = torch::optim::AdamW({ vertices }, torch::optim::AdamWOptions(0.008)); //auto scheduler = torch::optim::LRScheduler(optimizer, 500); // 准备数据点 std::vector<torch::Tensor> point_tensors; for (size_t i = 0; i < wy_nored.size(); ++i) { point_tensors.push_back(torch::tensor({ wy_nored[i], zh_nored[i] })); } auto points = torch::stack(point_tensors); std::cout << "vertices 张量的值:" << std::endl; auto vertices_accessor = points.accessor<float, 2>(); for (int i = 0; i < points.size(0); ++i) { for (int j = 0; j < points.size(1); ++j) { std::cout << vertices_accessor[i][j] << " "; } std::cout << std::endl; } // 计算目标面积 auto shifted_points = torch::roll(points, -1, 0); auto target_area = 0.5 * torch::abs(torch::sum( points.index({ torch::indexing::Slice(), 0 }) * shifted_points.index({ torch::indexing::Slice(), 1 }) - points.index({ torch::indexing::Slice(), 1 }) * shifted_points.index({ torch::indexing::Slice(), 0 }))); // 优化循环 for (int k = 0; k < iterations; ++k) { optimizer.zero_grad(); auto loss = calculate_gradient_descent_loss(vertices, points, target_area, lambda1); //[total_loss, distance_loss, area_loss] torch::Tensor total_loss = std::get<0>(loss); // 第一个元素 torch::Tensor distance_loss = std::get<1>(loss); // 第二个元素 torch::Tensor area_loss = std::get<2>(loss); // 第三个元素 // 输出损失信息 std::cout << "迭代 " << k + 1 << " | 总损失: " << total_loss.item<float>() << " | 距离损失: " << distance_loss.item<float>() << " | 面积损失: " << area_loss.item<float>() << std::endl; try { total_loss.backward(); } catch (const c10::Error& e) { std::cerr << "Caught c10::Error: " << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << "Caught std::exception: " << e.what() << std::endl; } vertices = apply_constraints(vertices); optimizer.step(); /* // 打印信息 std::cout << "迭代次数 " << k + 1 << ", 面积损失: " << area_loss.item<float>() << ", 距离损失: " << distance_loss.item<float>() << ", 总损失: " << total_loss.item<float>() << std::endl; */ } // 找到最近点 std::vector<int> vertex_indices = { 0, 1, 4, 5 }; std::vector<std::vector<float>> closest_points; for (int idx : vertex_indices) { auto vertex = vertices.index({ idx }).unsqueeze(0); auto distances = torch::norm(points - vertex, 2, 1); auto closest_idx = torch::argmin(distances).item<int>(); auto closest_point = points.index({ closest_idx }); closest_points.push_back({ closest_point.index({0}).item<float>(), closest_point.index({1}).item<float>() }); } // 反归一化 std::vector<std::vector<float>> closest_points_original; for (const auto& point : closest_points) { closest_points_original.push_back({ point[0] * (wmax - wmin) + wmin, point[1] * (zmax - zmin) + zmin }); } // 匹配原始数据点索引 std::vector<int> matched_indices; for (const auto& point : closest_points_original) { for (int i = 0; i < wySize; i++) { if (round(point[0] * 100.0f) / 100.0f == round(wy[i] * 100.0f) / 100.0f && round(point[1] * 100.0f) / 100.0f == round(zh[i] * 100.0f) / 100.0f) { matched_indices.push_back(i); break; } } } // 打印结果 if (print1) { std::cout << "反归一化后的最近点坐标:" << std::endl; for (size_t i = 0; i < closest_points_original.size(); ++i) { std::cout << "顶点 " << vertex_indices[i] << " 最近点: [" << closest_points_original[i][0] << ", " << closest_points_original[i][1] << "]" << std::endl; } } *resultSize = static_cast<int>(matched_indices.size()); // 动态分配结果数组 int* output = new int[matched_indices.size()]; std::copy(matched_indices.begin(), matched_indices.end(), output); return output; } extern "C" PARTICLESWARMMETHOD_API void free_int_array(int* arr) { delete[] arr; }
05-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值