Advertisement
dmkozyrev

equation

Apr 5th, 2015
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.70 KB | None | 0 0
  1. #include <iostream>
  2. #include <cmath>
  3. #include <vector>
  4. #include <stack>
  5. #include <algorithm>
  6. typedef long long i64;
  7. using namespace std;
  8.  
  9. bool increment(vector<i64>& pair, vector<i64>& limits);
  10. bool diophant(i64 a, i64 b, i64 c, i64 &x, i64 &y);
  11. vector <i64> perebor(vector<vector<i64>>& v, vector<i64>& p, vector<i64>& idempotents);
  12. vector <i64> decomposition(i64 n);
  13. vector <i64> find_x(vector<i64>& v, i64 n);
  14. vector <i64> idempotents_from_vector(vector <i64> & v);
  15. vector <i64> find_idempotents(vector<i64> &idempotents, vector<i64> &v_z);
  16. i64 calc_value(vector<i64>& v, i64 x, i64 n);
  17. i64 calc_number(vector<i64>&idempotents, vector<i64>& v_z, vector<i64>& v_ost);
  18.  
  19. int main(){
  20.     i64 m , n ; vector <i64> v ;
  21. //  Считывание степени многочлена и основания кольца вычетов
  22.     cout << "Input degree of polynom(m) and base of Zn: ";
  23.     cin >> m >> n;
  24. //  Считывание коэффициентов уравнения
  25.     cout << "Input a[0], a[1], ..., a[m] from polynom a[0]*x^m+a[1]*x^(m-1)+...+a[m] = 0: " << endl;
  26.     for (i64 i = 0 , a; i<=m; ++i){
  27.         cin >> a;
  28.         v.push_back(a);
  29.     }
  30. //  Вывод уравнения на экран
  31.     cout << "Equation: " << endl;
  32.     for (int i = 0; i <= m; ++i){
  33.         cout << v[i] << "*x^" << m-i;
  34.         if (i != m) cout << " + "; else cout << " = 0" << endl;
  35.     }
  36. //  Вывод разложения n на взаимно простые множители
  37.     cout << "Base: " << n << " --> ";
  38.     vector <i64> p = decomposition(n); //Разложение n на взаимно простые множители
  39.     for (int i = 0; i < p.size(); ++i){
  40.         cout << p[i];
  41.         if (i != p.size()-1) cout << " x "; else cout << endl;
  42.     }
  43. //  Получение в mas всех идемпотентов из вектора разложения n на взаимно простые множители
  44.     vector <i64> idempotents = idempotents_from_vector(p);
  45. //  Построение соответствия между идемпотентами исходного кольца вычетов по модулю n и изоморфному ему кольцу
  46.     idempotents = find_idempotents(idempotents, p);
  47.     vector<vector<i64>> x; // здесь будем хранить решения исходного уравнения в кольцах с основанием всех взаимно простых множителей n
  48.     for (auto &i:p){
  49.         x.push_back(find_x(v,i)); // ищем все решения и пушим их в вектор x
  50.         if (x.back().empty()){
  51.             cout << "This equation haven't solutions in ring on base = " << i;
  52.             return 0;
  53.         }
  54. //      Вывод решения для каждого элемента разложения n на взаимно простые множители
  55.         cout << "for p = " << i<< ": { ";
  56.         for(auto &j : x.back()) cout << j << " ";
  57.         cout << " }" << endl;
  58.     }
  59. //  Вывод надписи "ALL RIGHT" , если всё хорошо нашлось
  60.     cout << "ALL RIGHT" << endl;
  61.     vector<i64> answer = perebor(x, p, idempotents);
  62. //  Сортировка вектора ответов:
  63.     sort(answer.begin(), answer.end());
  64. //  Вывод ответа:
  65.     cout<<"ANSWER: ";
  66.     for(auto &i : answer) cout<<i<<" ";
  67. //  Реализация проверки:
  68. //    cout<<endl<<"CHECK THIS: "<<endl;
  69. //    for(auto &x : answer)
  70. //    cout<<"for x = "<<x<<": polynom(x) = "<< calc_value(v, x, n)<<endl;
  71. }
  72.  
  73.  
  74. bool increment(vector<i64>&pair, vector<vector<i64>>&v){
  75. // Функция осуществляет переход от текущего варианта к следующему во время перебора всех упорядоченных пар в изоморфном основному кольце
  76. // В векторе pair хранится индекс значения, которого нужно взять в векторе v, чтобы получить упорядоченную пару
  77.     for (i64 i = 0; i< v.size(); ++i){
  78.         pair[i]++;
  79.         if (pair[i] == v[i].size())
  80.             pair[i]=0;
  81.         else  
  82.             return true;
  83.     }
  84.     return false;
  85. }
  86.  
  87. vector<i64> perebor(vector<vector<i64>>& v, vector<i64>& p, vector<i64>& idempotents){
  88. // Перебирает все варианты упорядоченных пар в изоморфном основному кольцу кольце
  89. // Вектор p - разложение основания основного кольца на взаимно простые множители
  90. // Вектор idempotents - идемпотенты , поставленные в соответствие идемпотентам изоморфного кольца
  91.     vector<i64>pair, w, answer;
  92.     for(i64 i=0; i<v.size(); ++i){ pair.push_back(0); w.push_back(0);}
  93.     bool flag;
  94.     do {
  95.         for (i64 i=0; i<v.size(); ++i) w[i]=v[i][pair[i]];
  96.         answer.push_back(calc_number(idempotents, p, w));
  97.         flag = increment(pair, v);
  98.     } while (flag);
  99.     return answer;
  100. }
  101.  
  102. vector<i64>decomposition(i64 n){
  103. // Разложение n на взаимно простые множители
  104.     vector<i64>v;
  105.     for (i64 i = 2; i <= n; ++i)
  106.         if (n % i == 0)
  107.         {
  108.             v.push_back(i);
  109.             n /= i;
  110.             while (n % i == 0)
  111.             {
  112.                 n /= i;
  113.                 v.back() *= i;
  114.             }
  115.         }
  116.   return v;
  117. }
  118.  
  119. vector<i64>find_x(vector<i64>& v, i64 n){
  120. // Функция поиска решений уравнения с коэффициентами v в кольце по модулю n
  121.     vector<i64>x;
  122.     for (i64 i=0; i<n; ++i){
  123.         i64 y = calc_value(v, i, n);
  124.         if (y==0)x.push_back(i);
  125.     }
  126.     return x;
  127. }
  128.  
  129. i64 calc_value(vector<i64>& v, i64 x, i64 n){
  130. // Подсчет значения многочлена с коэффициентами v в точке x в кольце n по схеме горнера
  131.     i64 b=0;
  132.     for(auto &a : v){
  133.         b = x*b + a;
  134.         while (b>=n) b-=n;
  135.         while (b<0) b+=n;
  136.     }
  137.     return b;
  138. }
  139.  
  140. bool diophant(i64 a, i64 b, i64 c, i64 &x, i64 &y){
  141. //  Решение диофантового уравнения a*x + b*y = c методом Евклида
  142.     stack < i64 >q;
  143.     i64 r;
  144.     while (a % b != 0)
  145.     {
  146.         r = a % b;
  147.         q.push(a / b);
  148.         a = b;
  149.         b = r;
  150.     }
  151.     if (b != 1)
  152.     {
  153.         return false;
  154.     }
  155.     else
  156.     {
  157.         i64 temp;
  158.         x = 1;
  159.         y = q.top();
  160.         q.pop();
  161.         while (!q.empty())
  162.         {
  163.             temp = x;
  164.             x = -y;
  165.             y = -temp - q.top() * y;
  166.             q.pop();
  167.         }
  168.         x *= c;
  169.         y *= -c;
  170.         return true;
  171.     }
  172. }
  173.  
  174. vector < i64 > idempotents_from_vector(vector <i64> & v){
  175. //  Нахождение идемпотентов в кольце вычетов по модулю n, где n - произведение всех элементов вектора v, состоящего из взаимно простых чисел
  176.     i64 n = 1, m;
  177. //  Вычисление n
  178.     for (auto &i : v) n *= i;
  179. //  Двоичный перебор всех представлений n = a * b , где НОД(a,b) = 1;    
  180.     int c = v.size();
  181.     i64 limit = pow(2, c - 1), a, b, x, y;
  182.     vector < i64 > answer; // Будет хранить найденные идемпотенты
  183. //  Достаточно перебрать всего 2^(c-1) диофантовых уравнений, откуда мы вытащим один идемпотент
  184. //  И для найденного идемпотента х посчитаем 1-х парный идемпотент
  185.     for (i64 i = 1; i < limit; ++i)
  186.     {
  187.         m = i;
  188.         a = b = 1;
  189.         for (i64 j = 0; j < c; ++j)
  190.         {
  191.             if (m % 2 == 1)
  192.                 a *= v[j];
  193.             else
  194.                 b *= v[j];
  195.             m /= 2;
  196.         }
  197.         // Решаем полученное диофантово уравнение a*x + b*y = c
  198.         diophant(a, b, 1, x, y);
  199.         // a*x - один идемпотент
  200.         x *= a;
  201.         // Приводим х к нормальному виду: 0 <= x < n
  202.         while (x < 0) x += n;
  203.         while (x >= n) x -= n;
  204.         // Находим парный к нему идемпотент
  205.         y = n + 1 - x;
  206.         // Кидаем оба идемпотента в вектор
  207.         answer.push_back(x);
  208.         answer.push_back(y);
  209.     }
  210. //  Ну и возвращаем вектор
  211.     return answer;
  212. }
  213.  
  214. vector<i64> find_idempotents(vector<i64> &idempotents, vector<i64> &v_z){
  215. //  Вектор idempotents хранит все идемпотенты кольца вычетов с основанием n
  216. //  Вектор v_z хранит все основания колец вычетов , введенные пользователем
  217. //  Вектор v_ost хранит все остатки от сравнения по модулю с соответсвующим основанием кольца вычетов
  218.     i64 n = 1 ;
  219. //  Так как мы не передаём n , то посчитаем его как произведение всех элементов вектора v_z 
  220.     vector<i64> answer;
  221.     for (auto &i : v_z) { n *= i; answer.push_back(0);}
  222. //  Затем сопоставим каждому j-ому кольцу вычетов v_z[j] i-ый идемпотент кольца вычетов по модулю n 
  223.     for (auto &a : idempotents){
  224.         int t = -1, k = 0;
  225.         bool flag = true;
  226.         for(auto &b : v_z){
  227.             // Ищем единственную возможную единицу в остатке при делении a[i] на b[j] .
  228.             // Все остальные остатки при делении a[i] на b[k], где k != j, должны быть нулями
  229.             if (a % b == 1)
  230.                 if (t != -1){
  231.                     flag = false;
  232.                     break;
  233.                 } else
  234.                     t = k;
  235.             ++k;
  236.         }
  237.         // Если мы нашли соответсвующий идемпотент для v_z[t], то сразу умножаем его на v_ost[t] и прибавляем к искомому числу
  238.         if ( flag )
  239.             answer[t] = a;
  240.     }
  241. // Возвращаем искомое число
  242.     return answer; 
  243. }
  244.  
  245.  
  246. i64 calc_number(vector<i64>&idempotents, vector<i64>& v_z, vector<i64>& v_ost){
  247. //  Функция восстановления числа из изоморфного кольца в основной зная нужные идемпотенты основного кольца
  248.     i64 n=1, num = 0;
  249.     for (auto &i : v_z) n *= i;
  250.     for (int i=0; i<v_z.size(); ++i){
  251.         num += idempotents[i]*v_ost[i];
  252.         if (num>=n) num%=n;
  253.     }
  254.     return num;
  255. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement