dmkozyrev

399.cpp

Apr 14th, 2018
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.89 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <iostream>
  3. #include <iomanip>
  4. #include <algorithm>
  5. #include <vector>
  6. #include <string>
  7. #include <set>
  8. #include <queue>
  9. #include <ctime>
  10. #include <cstdlib>
  11. #include <cassert>
  12. #include <mutex>
  13. #include <thread>
  14.  
  15. const int INF = (int)1e9;
  16.  
  17. // Получить текущую дату и время в формате YYYY-MM-DD.HH:mm:ss
  18. const std::string currentDateTime() {
  19.     time_t     now = time(0);
  20.     struct tm  tstruct;
  21.     char       buf[80];
  22.     tstruct = *localtime(&now);
  23.     strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
  24.     std::string s(buf);
  25.     if (s.back() == '\n') s.pop_back();
  26.     return s;
  27. }
  28.  
  29. struct Solver {
  30.     int nRows;
  31.     int nCols;
  32.     int map[128][128];
  33.  
  34.     // Конструктор:
  35.     Solver(int nRows = 0, int nCols = 0, const std::vector<char>& field = {}) : nRows(nRows), nCols(nCols) {
  36.         assert(nRows * nCols == (int)field.size());
  37.         for (int r = 0, i = 0; r < nRows; ++r) {
  38.             for (int c = 0; c < nCols; ++c) {
  39.                 assert(0 == field[i] || 1 == field[i]);
  40.         map[r][c] = field[i++] * INF;
  41.             }
  42.         }
  43.     }
  44.  
  45.     // Функция, определяющая, существует ли путь из стартовой точки в конечную
  46.     bool isset_path() {
  47.         std::queue<std::pair<int, int>> q;
  48.         q.push({1, 1});
  49.         map[1][1] = 1;
  50.         while (!q.empty()) {
  51.             auto curr = q.front(); q.pop();
  52.             int r = curr.first, c = curr.second;
  53.             if (map[r+1][c] == 0) {
  54.                 map[r+1][c] = 1;
  55.                 q.push({r+1, c});
  56.             }
  57.             if (map[r-1][c] == 0) {
  58.                 map[r-1][c] = 1;
  59.                 q.push({r-1, c});
  60.             }
  61.             if (map[r][c+1] == 0) {
  62.                 map[r][c+1] = 1;
  63.                 q.push({r, c+1});
  64.             }
  65.             if (map[r][c-1] == 0) {
  66.                 map[r][c-1] = 1;
  67.                 q.push({r, c-1});
  68.             }
  69.         }
  70.         bool result = map[nRows-2][nCols-2];
  71.         backup();
  72.         return result;
  73.     }
  74.  
  75.     // Откатить изменения на поле к первоначальному виду:
  76.     void backup() {
  77.         for (int r = 0; r < nRows; ++r) {
  78.             for (int c = 0; c < nCols; ++c) {
  79.                 map[r][c] = (map[r][c] == INF) ? INF : 0;
  80.             }
  81.         }
  82.     }
  83.  
  84.     // Промоделировать действия жука для получения ответа:
  85.     int solve() {
  86.         if (!isset_path()) {
  87.             return -1;
  88.         }
  89.         int r = 1, c = 1, dir = 0, answ = 0;
  90.         const int dr[4] = { 1, 0, -1,  0};
  91.         const int dc[4] = { 0, 1,  0, -1};
  92.         do {
  93.             map[r][c]++;
  94.             int min = std::min({
  95.                 map[r-1][c], map[r+1][c], map[r][c+1], map[r][c-1]
  96.             });
  97.  
  98.             if (map[r+dr[dir]][c+dc[dir]] != min) {
  99.                 for (int next = 0; next < 4; ++next) {
  100.                     if (map[r+dr[next]][c+dc[next]] == min) {
  101.                         dir = next;
  102.                         break;
  103.                     }
  104.                 }
  105.             }
  106.             ++answ;
  107.             r += dr[dir];
  108.             c += dc[dir];
  109.         } while (!(r == nRows-2 && c == nCols-2));
  110.         backup();
  111.         return answ;
  112.     }
  113. };
  114.  
  115. struct Mask {
  116.     int row, col;
  117.     std::vector<std::vector<char>> data;
  118.  
  119.     static Mask gen(int row, int col, int side, int p0, int p1) {
  120.         std::vector<std::vector<char>> data(side, std::vector<char>(side));
  121.         for (int i = 0; i < side; ++i)
  122.             for (int j = 0; j < side; ++j)
  123.                 data[i][j] = (rand() % (p0 + p1) >= p0);
  124.         return Mask{row, col, std::move(data)};
  125.     }
  126. };
  127.  
  128. /*
  129. bool operator<(const Square& a, const Square& b) {
  130.     return a.row < b.row || (a.row == b.row && (a.col < b.col || (a.col == b.col && a.side < b.side)));
  131. } */
  132.  
  133. // Генерация случайных масок
  134. std::vector<Mask> gen_squares(int nRows, int nCols, int min_count, int max_count, int max_side, int p0, int p1) {
  135.     std::vector<Mask> answer;
  136.     const int count = rand() % (max_count - min_count + 1) + min_count;
  137.     assert(min_count <= count && count <= max_count);
  138.     while ((int)answer.size() < count) {
  139.         const int side = rand() % max_side + 1;
  140.         const int row = rand() % (nRows-side-1)+1;
  141.         const int col = rand() % (nCols-side-1)+1;
  142.         assert(1 <= side && side <= max_side);
  143.         assert(1 <= row && row <= nRows-2);
  144.         assert(1 <= col && col <= nCols-2);
  145.         auto mask = Mask::gen(row, col, side, p0, p1);
  146.         // Если стартовая клетка или конечная задета, то фигура не подходит:
  147.         if ((row == 1 && col == 1 && mask.data[0][0]) || (row + side - 1 == nRows-2 && col + side - 1 == nCols-2 && mask.data.back().back())) {
  148.             continue;
  149.         }
  150.         answer.push_back(mask);
  151.     }
  152.     return answer;
  153. }
  154.  
  155. // Применение инверсий внутри квадратов к полю:
  156. std::vector<char> modify(int nRows, int nCols, std::vector<char> field, const std::vector<Mask>& squares) {
  157.     assert(nRows*nCols == (int)field.size());
  158.     for (const auto& s : squares) {
  159.         for (int dr = 0; dr < (int)s.data.size(); ++dr) {
  160.             for (int dc = 0; dc < (int)s.data[0].size(); ++dc) {
  161.                 int row = s.row + dr;
  162.                 int col = s.col + dc;
  163.                 if (s.data[dr][dc]) {
  164.                     auto& it = field[row * nCols + col];
  165.                     it = 1 - it;
  166.                 }
  167.             }
  168.         }
  169.     }
  170.     return field;
  171. }
  172.  
  173. // Запись поля в файл:
  174. void print_field(const int nRows, const int nCols, const std::vector<char>& field, const std::string& filename) {
  175.     auto file = fopen(filename.c_str(), "wt");
  176.     assert(file != 0);
  177.     fprintf(file, "%d %d\n", nRows, nCols);
  178.     for (int r = 0; r < nRows; ++r) {
  179.         for (int c = 0; c < nCols; ++c) {
  180.             fprintf(file, "%c", field[r*nCols+c] == 1 ? '@' : ' ');
  181.         }
  182.         fprintf(file, "\n");
  183.     }
  184.     fclose(file);
  185. }
  186.  
  187. // Чтение поля из файла:
  188. std::vector<char> read_field(int &nRows, int& nCols, const std::string& filename) {
  189.     std::vector<char> field;
  190.     auto file = fopen(filename.c_str(), "rt");
  191.     assert(file != 0);
  192.     fscanf(file, "%d %d", &nRows, &nCols); fscanf(file, "\n");
  193.     for (int r = 0; r < nRows; ++r) {
  194.         char buf[101];
  195.     fscanf(file, "%[^\n]s", buf); fscanf(file, "\n");
  196.         for (int c = 0; c < nCols; ++c) {
  197.             field.push_back(buf[c] == '@');
  198.         }
  199.     }
  200.     fclose(file);
  201.     return field;
  202. }
  203.  
  204. // Многопоточный алгоритм поиска:
  205. void search(
  206.     const int nRows,         // кол-во строк
  207.     const int nCols,         // кол-во столбцов
  208.     std::vector<char> field, // начальное приближение поля
  209.     int nThreads,            // кол-во потоков
  210.     const int min_count,     // минимальное кол-во квадратов инверсий
  211.     const int max_count,     // максимальное кол-во квадратов инверсий
  212.     const int max_side,      // максимальная сторона квадрата инверсий
  213.     const int p0,            // вероятность появления нуля в маске p0 / (p0+p1)
  214.     const int p1             // вероятность появления единицы в маске p1 / (p0+p1)
  215. ) {
  216.     assert(nRows * nCols == (int)field.size());
  217.     assert(nThreads >= 1);
  218.  
  219.     srand(time(0));
  220.  
  221.     nThreads = std::min(nThreads, (int)std::thread::hardware_concurrency());
  222.  
  223.     std::mutex mtx;
  224.  
  225.     int curr = Solver(nRows, nCols, field).solve();
  226.  
  227.     std::vector<std::thread> threads;
  228.     std::vector<uint64_t> Time(1+nThreads, clock());
  229.  
  230.     for (int i = 1; i <= nThreads; ++i) {
  231.         threads.push_back(std::thread([&, id = i]{
  232.             while (1) {
  233.                 mtx.lock();
  234.                 int answ = curr;
  235.                 auto fld = field;
  236.                 mtx.unlock();
  237.  
  238.                 fld = modify(nRows, nCols, fld, gen_squares(nRows, nCols, min_count, max_count, max_side, p0, p1));
  239.  
  240.                 int temp = Solver(nRows, nCols, fld).solve();
  241.                 auto dt = clock() - Time[id];
  242.                 if (dt >= 60 * CLOCKS_PER_SEC) {
  243.                     std::cout << currentDateTime() << ": thread #" << id << " working, don't worry, curr = " << std::setw(9) << curr << std::endl;
  244.                     Time[id] += dt;
  245.                 }
  246.         if (temp >= answ) {
  247.                     mtx.lock();
  248.                     if (temp >= curr) {
  249.                         if (temp > curr) {
  250.                             std::cout << currentDateTime() << ": thread #" << id << " got result = " << std::setw(9) << temp << std::endl;
  251.                             char buf[101]; sprintf(buf, "test%09d.txt", temp);
  252.                             print_field(nRows, nCols, fld, buf);
  253.                         }
  254.                         field = fld;
  255.                         curr = temp;
  256.                     }
  257.                     mtx.unlock();
  258.                 }
  259.             }
  260.             return;
  261.         }));
  262.     }
  263.  
  264.     for (auto & t : threads) t.join();
  265. }
  266.  
  267. // Генерация случайного поля размера nRows x nCols
  268. // гарантируется, что на сгенерированном поле будет проход:
  269. // (1, 1) --> (nRows-2, nCols-2)
  270. std::vector<char> rand_field(int nRows, int nCols) {
  271.     srand(time(0));
  272.  
  273.     std::vector<char> field(nRows*nCols);
  274.  
  275.     for (int r = 0; r < nRows; ++r)
  276.         field[r*nCols] = field[r*nCols+nCols-1] = 1;
  277.  
  278.     for (int c = 0; c < nCols; ++c)
  279.         field[c] = field[(nRows-1)*nCols+c] = 1;
  280.  
  281.     do {
  282.         for (int r = 1; r <= nRows-2; ++r) {
  283.             for (int c = 1; c <= nCols-2; ++c) {
  284.                 if ((r == 1 && c == 1) || (r == nRows-2 && c == nCols-2)) {
  285.                     field[r*nCols+c] = 0;
  286.                 } else {
  287.                     field[r*nCols+c] = rand() % 2;
  288.                 }
  289.             }
  290.         }
  291.     } while (Solver(nRows, nCols, field).solve() == -1);
  292.     return field;
  293. }
  294.  
  295. int main(int argc, char* argv[]) {
  296.     assert((argc-1) % 2 == 0);
  297.  
  298.     std::string filename = "input.txt";
  299.     int nThreads = std::thread::hardware_concurrency();
  300.     int minCount = 1;
  301.     int maxCount = 6;
  302.     int maxSide  = 3;
  303.     int pZeros   = 1;
  304.     int pOnes    = 3;
  305.  
  306.     std::cout << "Params from command line:" << std::endl;
  307.     for (int i = 1; i < argc; i += 2) {
  308.         std::cout << "\t" << argv[i] << " = " << argv[i+1] << std::endl;
  309.     std::string command(argv[i]);
  310.         if (command == "nThreads") nThreads = atoi(argv[i+1]);
  311.         if (command == "minCount") minCount = atoi(argv[i+1]);
  312.         if (command == "maxCount") maxCount = atoi(argv[i+1]);
  313.         if (command == "maxSide") maxSide = atoi(argv[i+1]);
  314.         if (command == "pZeros") pZeros = atoi(argv[i+1]);
  315.         if (command == "pOnes") pOnes = atoi(argv[i+1]);
  316.         if (command == "filename") filename = argv[i+1];
  317.     }
  318.     std::cout << std::endl << "Params:\n";
  319.     std::cout << "\tfilename = " << filename << std::endl;
  320.     std::cout << "\tnThreads = " << nThreads << std::endl;
  321.     std::cout << "\tminCount = " << minCount << std::endl;
  322.     std::cout << "\tmaxCount = " << maxCount << std::endl;
  323.     std::cout << "\tmaxSide  = " << maxSide  << std::endl;
  324.     std::cout << "\tpZeros   = " << pZeros   << std::endl;
  325.     std::cout << "\tpOnes    = " << pOnes    << std::endl;
  326.     int nRows = 21, nCols = 31;
  327.     //auto field = rand_field(nRows, nCols);
  328.     auto field = read_field(nRows, nCols, filename);
  329.     //std::cout << "rand field success!" << std::endl;
  330.     search(nRows, nCols, field, nThreads, minCount, maxCount, maxSide, pZeros, pOnes);
  331.     return 0;
  332. }
Advertisement
Add Comment
Please, Sign In to add comment