The_Law

Untitled

May 23rd, 2023
1,138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.12 KB | None | 0 0
  1. #include <cmath>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <vector>
  5.  
  6. const unsigned int MAX_ITER = 5;
  7. const double EPS = 1e-8;
  8.  
  9. unsigned short randomInRange(unsigned short lb, unsigned short ub)
  10. {
  11.     return lb + std::rand() % (ub - lb + 1);
  12. }
  13.  
  14. bool isStopCriteriaReached(double& prev, double& curr, double eps)
  15. {
  16.     return fabs(prev - curr) < eps;
  17. }
  18.  
  19. void getL(
  20.     double* lambda,
  21.     unsigned int* p, unsigned short** w,
  22.     unsigned short n, unsigned short m,
  23.     unsigned short gIndx,
  24.     double* l
  25. ) {
  26.     for (unsigned short i = 0; i < n; ++i) {
  27.         l[i] = p[i];
  28.  
  29.         for (unsigned short j = 0; j < m; ++j) {
  30.             if (j != gIndx) {
  31.                 l[i] -= w[i][j] * lambda[j];
  32.             }
  33.         }
  34.     }
  35. }
  36.  
  37. double getD(
  38.     unsigned short n, unsigned short m,
  39.     double* l, unsigned short* x,
  40.     unsigned short* c, double* lambda,
  41.     unsigned short gIndx
  42. ) {
  43.     double res = 0;
  44.     for (unsigned short i = 0; i < n; ++i) {
  45.         res += l[i] * x[i];
  46.     }
  47.     for (unsigned short j = 0; j < m; ++j) {
  48.         if (j != gIndx) {
  49.             res += c[j] * lambda[j];
  50.         }
  51.     }
  52.     return res;
  53. }
  54.  
  55. void getSubgrad(
  56.     unsigned short n, unsigned short m,
  57.     unsigned short** w, unsigned short gIndx,
  58.     unsigned short* c,
  59.     unsigned short* x,
  60.     short* subgrad
  61. ) {
  62.     for (unsigned short j = 0; j < m; ++j) {
  63.         if (j != gIndx) {
  64.             subgrad[j] = c[j];
  65.             for (unsigned short i = 0; i < n; ++i) {
  66.                 subgrad[j] -= w[i][j] * x[i];
  67.             }
  68.         }
  69.     }
  70. }
  71.  
  72. double getSubgradNorm(
  73.     unsigned short m, unsigned short gIndx,
  74.     short* subgrad
  75. ) {
  76.     double res = 0;
  77.     for (unsigned short j = 0; j < m; ++j) {
  78.         if (j != gIndx) {
  79.             res += subgrad[j] * subgrad[j];
  80.         }
  81.     }
  82.  
  83.     return sqrt(res);
  84. }
  85.  
  86. void getNextLambda(
  87.     unsigned short m, unsigned short gIndx,
  88.     double* lambda, short* subgrad,
  89.     double step
  90. ) {
  91.     double subgradNorm = getSubgradNorm(m, gIndx, subgrad);
  92.  
  93.     for (unsigned short j = 0; j < m; ++j) {
  94.         if (j != gIndx) {
  95.             lambda[j] -= step * subgrad[j] / (subgradNorm + EPS);
  96.             lambda[j] = std::max(0., lambda[j]);
  97.         }
  98.     }
  99. }
  100.  
  101. struct Node
  102. {
  103.     short v, prev;
  104.     int w;
  105.     double p;
  106. };
  107.  
  108. Node createNode(short v, short prev, int w, double p)
  109. {
  110.     Node res;
  111.     res.v = v;
  112.     res.prev = prev;
  113.     res.w = w;
  114.     res.p = p;
  115.     return res;
  116. }
  117.  
  118. void solve1DimBackpack(
  119.     unsigned short n, unsigned short c,
  120.     double* p, unsigned short* w,
  121.     double& ans, unsigned short* x
  122. ) {
  123.     std::vector<Node>* D = new std::vector<Node>[n + 1]; // 1-indexation per first dim
  124.     D[0].push_back(createNode(-1, -1, 0, 0));
  125.  
  126.     for (short i = 0; i < n; ++i) { // iterating items  
  127.         short it0 = 0;
  128.         short it1 = 0;
  129.  
  130.         while (it0 < D[i].size() && it1 < D[i].size()) {
  131.             // both tuples are not empty
  132.             Node node0 = createNode(0, it0, D[i][it0].w, D[i][it0].p);
  133.  
  134.             if (D[i][it1].w + w[i] > c) {
  135.                 ++it1; // skip 1, too tight borders
  136.                 continue;
  137.             }
  138.             Node node1 = createNode(1, it1, D[i][it1].w + w[i], D[i][it1].p + p[i]);
  139.  
  140.             if ( // dominated, 0 > 1
  141.                 node0.w <= node1.w &&
  142.                 node0.p >= node1.p
  143.                 ) {
  144.                 ++it1; // just skip 1
  145.             }
  146.             else if ( // dominated, 1 > 0
  147.                 node1.w <= node0.w &&
  148.                 node1.p >= node0.p
  149.                 ) {
  150.                 ++it0; // just skip 0
  151.             }
  152.             else if ( // ordinary, 0 > 1
  153.                 node0.w <= node1.w
  154.                 ) {
  155.                 D[i + 1].push_back(node0);
  156.                 ++it0; // next 0
  157.             }
  158.             else if ( // ordinary, 1 > 0
  159.                 node1.w <= node0.w
  160.                 ) {
  161.                 D[i + 1].push_back(node1);
  162.                 ++it1; // next 1
  163.             }
  164.         }
  165.  
  166.         // fill the rest
  167.         while (it0 < D[i].size()) {
  168.             Node node0 = createNode(0, it0, D[i][it0].w, D[i][it0].p);
  169.             if ( // ignore dominated
  170.                 !D[i + 1].empty() &&
  171.                 D[i + 1].back().w <= node0.w &&
  172.                 D[i + 1].back().p >= node0.p
  173.                 ) {
  174.                 ++it0; // just skip 1
  175.             }
  176.             else {
  177.                 D[i + 1].push_back(node0);
  178.                 ++it0;
  179.             }
  180.         }
  181.  
  182.         while (it1 < D[i].size()) {
  183.             if (D[i][it1].w + w[i] > c) {
  184.                 ++it1; // skip 1, too tight borders
  185.                 continue;
  186.             }
  187.             Node node1 = createNode(1, it1, D[i][it1].w + w[i], D[i][it1].p + p[i]);
  188.  
  189.             if ( // ignore dominated
  190.                 !D[i + 1].empty() &&
  191.                 D[i + 1].back().w <= node1.w &&
  192.                 D[i + 1].back().p >= node1.p
  193.                 ) {
  194.                 ++it1; // just skip 1
  195.             }
  196.             else {
  197.                 D[i + 1].push_back(node1);
  198.                 ++it1;
  199.             }
  200.         }
  201.     }
  202.  
  203.     // answer backtracking
  204.     int itN = n;
  205.     int itL = D[itN].size() - 1;
  206.  
  207.     std::vector<short> path;
  208.  
  209.     while (D[itN][itL].prev != -1) {
  210.         if (D[itN][itL].v == 1) {
  211.             path.push_back(itN - 1); // cast 1-indexation to 0
  212.         }
  213.         itL = D[itN][itL].prev;
  214.         --itN;
  215.     }
  216.  
  217.     ans = D[n].back().p;
  218.  
  219.     for (short i = 0; i < path.size(); ++i) {
  220.         x[path[i]] = 1;
  221.     }
  222.  
  223.     delete[] D;
  224. }
  225.  
  226. double getLagrangianEstimation(
  227.     unsigned short n, unsigned short m,
  228.     unsigned short* c, unsigned int* p,
  229.     unsigned short** w
  230. ) {
  231.     unsigned int currIter = 1;
  232.     unsigned short gIndx = randomInRange(0, m - 1); //selected subject index
  233.     double* currLambda = new double[m];
  234.     double prevD = -1e9;
  235.     double D;
  236.  
  237.     for (unsigned short i = 0; i < m; ++i) {
  238.         currLambda[i] = 1;
  239.     }
  240.  
  241.     while (currIter <= MAX_ITER) {
  242.         // implementing dual problem
  243.         double* l = new double[n];
  244.         getL(currLambda, p, w, n, m, gIndx, l);
  245.  
  246.         unsigned short* x = new unsigned short[n];
  247.         for (unsigned short i = 0; i < n; ++i) {
  248.             x[i] = 0;
  249.         }
  250.  
  251.         // getting x*(lambda), D(lambda)
  252.         unsigned short* wPer1Dim = new unsigned short[n];
  253.         for (unsigned short i = 0; i < n; ++i) {
  254.             wPer1Dim[i] = w[i][gIndx];
  255.         }
  256.  
  257.         double currAns = 0;
  258.         solve1DimBackpack(n, c[gIndx], l, wPer1Dim, currAns, x);
  259.         delete[] wPer1Dim;
  260.  
  261.         D = getD(n, m, l, x, c, currLambda, gIndx);
  262.  
  263.         // checking stopping criteria
  264.         if (isStopCriteriaReached(D, prevD, EPS)) {
  265.             delete[] l, x;
  266.             break;
  267.         }
  268.  
  269.         // moving to next step
  270.         if (currIter + 1 < MAX_ITER) {
  271.             double step = 1. / (currIter + 1);
  272.             short* subgrad = new short[m];
  273.             getSubgrad(n, m, w, gIndx, c, x, subgrad);
  274.             getNextLambda(m, gIndx, currLambda, subgrad, step);
  275.  
  276.             prevD = D;
  277.  
  278.             delete[] subgrad;
  279.         }
  280.  
  281.         delete[] l, x;
  282.         ++currIter;
  283.     }
  284.  
  285.     delete[] currLambda;
  286.  
  287.     // output
  288.     return D;
  289. }
  290.  
  291. void branchAndBoundMethod(
  292.     unsigned short currIt,
  293.     unsigned short n, unsigned short m,
  294.     unsigned short* c, unsigned int* p,
  295.     unsigned short** w,
  296.     unsigned short* x,
  297.     unsigned short* recordX,
  298.     unsigned int& recordValue,
  299.     unsigned int currObjectiveValue
  300. ) {
  301.     // recursion stop criteria
  302.     if (currIt >= n) {
  303.         if (currObjectiveValue > recordValue) {
  304.             for (int i = 0; i < n; ++i) {
  305.                 recordX[i] = x[i];
  306.             }
  307.             recordValue = currObjectiveValue;
  308.         }
  309.         return;
  310.     }
  311.  
  312.     // estimate the 1-subtree
  313.     bool isValidSubtree = true;
  314.     unsigned short* unfixedC = new unsigned short[m];
  315.     for (unsigned short j = 0; j < m; ++j) {
  316.         unfixedC[j] = c[j] - w[currIt][j];
  317.         if (w[currIt][j] > c[j]) {
  318.             isValidSubtree = false;
  319.         }
  320.     }
  321.  
  322.     unsigned int* unfixedP = new unsigned int[n - currIt - 1];
  323.     for (unsigned short i = 0; i < n - currIt - 1; ++i) {
  324.         unfixedP[i] = p[i + currIt + 1];
  325.     }
  326.  
  327.     unsigned short** unfixedW = new unsigned short* [n - currIt - 1];
  328.     for (unsigned short i = 0; i < n - currIt - 1; ++i) {
  329.         unfixedW[i] = new unsigned short[m];
  330.         for (unsigned short j = 0; j < m; ++j) {
  331.             unfixedW[i][j] = w[i + currIt + 1][j];
  332.         }
  333.     }
  334.  
  335.     double D = 0;
  336.     if (isValidSubtree) {
  337.         D = getLagrangianEstimation(
  338.             n - currIt - 1, m,
  339.             unfixedC, unfixedP, unfixedW
  340.         );
  341.     }
  342.  
  343.     // 1-branching attempt
  344.     x[currIt] = 1;
  345.     if (isValidSubtree && currObjectiveValue + p[currIt] + D > recordValue) {
  346.         for (unsigned short j = 0; j < m; ++j) {
  347.             c[j] = c[j] - w[currIt][j];
  348.         }
  349.         branchAndBoundMethod(
  350.             currIt + 1,
  351.             n, m,
  352.             c, p, w,
  353.             x, recordX,
  354.             recordValue,
  355.             currObjectiveValue + p[currIt]
  356.         );
  357.         for (unsigned short j = 0; j < m; ++j) {
  358.             c[j] = c[j] + w[currIt][j];
  359.         }
  360.     }
  361.  
  362.     // estimate the 0-subtree
  363.     for (unsigned short j = 0; j < m; ++j) {
  364.         unfixedC[j] = c[j];
  365.     }
  366.  
  367.     D = getLagrangianEstimation(
  368.         n - currIt - 1, m,
  369.         unfixedC, unfixedP, unfixedW
  370.     );
  371.  
  372.     // 0-branching attempt
  373.     x[currIt] = 0;
  374.     if (currObjectiveValue + D > recordValue) {
  375.         branchAndBoundMethod(
  376.             currIt + 1,
  377.             n, m,
  378.             c, p, w,
  379.             x, recordX,
  380.             recordValue,
  381.             currObjectiveValue
  382.         );
  383.     }
  384.  
  385.     delete[] unfixedC, unfixedP;
  386.     for (unsigned short i = 0; i < n - currIt - 1; ++i) {
  387.         delete[] unfixedW[i];
  388.     }
  389.  
  390.     return;
  391. }
  392.  
  393. int main()
  394. {
  395.     // input
  396.     unsigned short n, m;
  397.     scanf("%hu %hu", &n, &m);
  398.  
  399.     unsigned int* p = new unsigned int[n];
  400.     for (unsigned short i = 0; i < n; ++i) {
  401.         scanf("%u", &p[i]);
  402.     }
  403.  
  404.     unsigned short* c = new unsigned short[m];
  405.     for (unsigned short i = 0; i < m; ++i) {
  406.         scanf("%hu", &c[i]);
  407.     }
  408.  
  409.     unsigned short** w = new unsigned short* [n];
  410.     for (unsigned short i = 0; i < n; ++i) {
  411.         w[i] = new unsigned short[m];
  412.     }
  413.     for (unsigned short j = 0; j < m; ++j) {
  414.         for (unsigned short i = 0; i < n; ++i) {
  415.             scanf("%hu", &w[i][j]);
  416.         }
  417.     }
  418.  
  419.     // algo
  420.     unsigned short* x = new unsigned short[n];
  421.     unsigned short* ans = new unsigned short[n];
  422.     unsigned int ansValue = 0;
  423.     unsigned int currObjectiveValue = 0;
  424.  
  425.     branchAndBoundMethod(
  426.         0,
  427.         n, m,
  428.         c, p, w,
  429.         x, ans,
  430.         ansValue,
  431.         currObjectiveValue
  432.     );
  433.  
  434.     printf("%d\n", ansValue);
  435.     for (unsigned short i = 0; i < n; ++i) {
  436.         printf("%d\n", ans[i]);
  437.     }
  438.  
  439.     // memory clean
  440.     delete[] c, p, x, ans;
  441.     for (unsigned short i = 0; i < n; ++i) {
  442.         delete[] w[i];
  443.     }
  444.  
  445.     return 0;
  446. }
Advertisement
Add Comment
Please, Sign In to add comment