循环向量 - 找到尽可能少的“成本”(来自CodeChef)

时间:2016-09-26 14:55:35

标签: c++ algorithm

这是来自Codechef的问题,但请耐心等待。 https://www.codechef.com/ZCOPRAC/problems/ZCO12004

比赛是为了准备在印度举行的区域计算奥林匹克运动会,所以它不是一场竞争性的比赛,我可以从中获得这样的比赛。只需要一些帮助就可以看出我的代码有什么问题,因为我有一种感觉,我忽略了一些大而愚蠢的东西。 :P

问题基本上表明:

  

想象一下,有一个向量或数组,使得最后一个元素是   与第一个相关联。找到添加的最低总和   每个相邻元素对中的至少一个。 (请参阅链接)   因此,通过添加1 + 1 + 2,{1,2,1,2,2}输出的答案将是4。

这是我的解决方案:

它的作用基本上是它向后迭代,从向量的末尾到开头,并存储从向量M中可以实现的最低可能总和,在向量M中。基本上使用动态编程完成。 / p>

M的前两个元素是可能的答案。然后我做一些检查,看看哪些是可能的。如果M [1]小于M [0],那么数组/向量的最后一个元素应该包含在M [1]中计算的总和中。

#include <algorithm>
#include <iostream>
#include <vector>


#define print(arr) for(auto pos = arr.begin(); pos != arr.end(); ++pos) cout << *pos << " "; cout << endl;
typedef long long int ll;
using namespace std;

int main() {


    int N;
    ll x;
    cin >> N;
    vector <ll> A;
    vector <ll> M(N+2);
    fill(M.begin(),M.end(),0);
    for (int i = 0; i < N; i++) {
        cin >> x;
        A.push_back(x);

    }

    for (int i = N-1; i >= 0; i--) {
        M[i] = A[i]+*min_element(M.begin()+i+1, M.begin()+i+3);
    }

    if (M[0] <= M[1]) cout << M[0] << endl;
    else if (M[1] < M[0]) {
        if (M[N-1] <= (M[N-2])) cout << M[1] << endl;
        else cout << M[0] << endl;
    }

}

但是,我无法在子任务2中传递2个测试用例。我认为我的代码的最后一部分是不正确的。知道我可能做错了吗?要不然,或者我误解了这个问题。术语“相邻对”有点含糊不清。因此,如果有4个数字3,4,5,6相邻对是否意味着相邻对是{(3,4)(4,5)(5,6)(6,3)}或{或者(3,4) )和(5,6)或(4,5)和(6,3)}?我的代码考虑前者。

编辑:

非常感谢@User_Targaryen清除了对这个问题的疑虑!基本上我的实现和你的一样,因为我使用动态编程背后的想法是一样的。只有在这种情况下我的M(你的dp)与你的相反。无论如何我得到了AC! :)(我留下了一些愚蠢的调试声明,并且想知道15分钟出了什么问题xD)更新的解决方案:

#include <algorithm>
#include <iostream>
#include <vector>

#define print(arr) for(auto pos = arr.begin(); pos != arr.end(); ++pos) cout << *pos << " "; cout << endl;
typedef long long int ll;
using namespace std;



int main() {


    int N;
    ll x, sum = 0;
    cin >> N;
    vector <ll> A;
    vector <ll> M(N+2);
    fill(M.begin(),M.end(),0);
    for (int i = 0; i < N; i++) {
        cin >> x;
        A.push_back(x);
    }

    for (int i = N-1; i >= 0; i--) {
        M[i] = A[i]+*min_element(M.begin()+i+1, M.begin()+i+3);
    }

    //print(M);

    reverse(A.begin(), A.end());
    vector <ll> M2(N+2);
    fill(M2.begin(),M2.end(),0);
    for (int i = N-1; i >= 0; i--) {
        M2[i] = A[i]+*min_element(M2.begin()+i+1, M2.begin()+i+3);
    }
    //print(M2);


    cout << min(M[0], M2[0]) << endl;

}

2 个答案:

答案 0 :(得分:2)

我在这里附上我接受的解决方案:

#include<iostream>
using namespace std;

int main()
{
   int i,j,k,n;
   cin>>n;
   int a[n],dp1[n],dp2[n];
   int ans;
   for(i=0;i<n;i++)
   {
      cin>>a[i];
      dp1[i]=0;
      dp2[i]=0;
   }
   if(n <= 2)
     cout<< min(a[0],a[1]);

   else{
     i = 2;
     dp1[0] = a[0];
     dp1[1] = a[1];
     while (i < n){
        dp1[i] = a[i] + min(dp1[i-1],dp1[i-2]);
        i = i + 1;
     }

     dp2[0] = a[n-1];
     dp2[1] = a[n-2];
     i = n-3;
     j = 2;
     while(i >= 0){
        dp2[j] = a[i] + min(dp2[j-1],dp2[j-2]);
        i = i - 1;
        j = j + 1;
     }
     ans = min(dp1[n-1], dp2[n-1]);
     cout<<ans;
   }
   return 0;
}

dp1[i]表示迄今为止最合适的解决方案是在解决方案中包含i-th元素

dp2[i]表示迄今为止最合适的解决方案是在解决方案中包含i-th元素

dp1[]从左到右计算,而dp2[]从右到左计算

minimumdp1[n-1]的{​​{1}}是最终答案。

Solution Report

我完成了你的作业!

编辑 @Alex 动态编程是一项非常难以教授的内容。这是某种做法自然而然的事情。让我们考虑一下我的解决方案(暂时忘掉你的解决方案):

dp2[n-1]意味着我在解决方案中明确包含了最后一个元素,并且满足任何2个相邻元素中的至少一个需要选择的约束,因为它始终如下:

dp1[n-1]

dp1[i] = a[i] + min(dp1[i-1],dp1[i-2]); 意味着我在解决方案中明确包含了第一个元素,并且也满足了任何2个相邻元素中至少有一个需要选择的约束。

所以,上述两个中的最小值将给出最终结果。

答案 1 :(得分:1)

M[i]数组中的想法是“解决方案的最低成本,假设其中包含索引i”。

条件if (M[0] <= M[1])表示“如果包含索引0优于不包括它,则完成”。

如果这种情况不成立,那么,首先,支票if (M[1] < M[0])是多余的 - 将其删除。它不会修复任何错误,但至少会减少混淆。

如果条件为false,则应输出M[1],但前提是它与有效解决方案相对应。也就是说,由于未选择索引0,因此应选择最后一个索引。但是,使用您的数据结构,无法知道M [1]是否对应于选择最后一个索引的解决方案 - 此信息将丢失。

要解决此问题,请考虑构建两个数组 - 例如数组L,其含义为“解决方案的最低成本,假设其中包含索引i以及索引N-1包含在其中

然后,在您的计划结束时,输出最小值M[0]L[1]