找到上包络的最大长度

时间:2014-08-17 17:44:14

标签: c++ algorithm dynamic-programming

我正在解决一个问题 Rectangles Perimeter 问题是

给定n个矩形,编号从1到n。根据,我们将它们从左到右紧紧地放在轴OX上 矩形的数字。每个矩形都保留在轴OX上 更短或更长的一面(见下图)。计算 上包络线的长度,即所获得的周长 图减去左,右和的长度 图片的底部直线段。写程序到 找到上限线的最大可能长度。

例如

enter image description here

一种配置,它产生上包络的最大长度 线,在图片上显示。 上部包络线由DC,CG,GF,FJ,JI,IM组成, ML,LP和PO。 总长度为5 + 6 + 3 + 7 + 10 + 13 + 7 + 12 + 5 = 68

输入

  

在标准输入的第一行,n的值为   书面。在接下来的n行中,给出了两个整数 -   a_i和b_i - 第i个矩形的边长。约束:   0< n< 1000; 0< a_i< b_i< 1000,每个i = 1,2,...,n。

示例输入:

5 
2 5 
3 8 
1 10 
7 14 
2 5 

输出

在标准输出的一行上,你的程序应该写 结果为正整数

示例输出

68

我正在使用一种方法,我逐一修复矩形并找到上包络的最大长度然后使用该ans来查找包络的下一个最大长度等等。

我的代码是......

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <deque>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <string>
#include <vector>
#include <functional>
#include <numeric>
#include <utility>
#include<string.h>

using namespace std;

typedef double dbl;
typedef float flt;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef pair<ll,int> pli;


#define eps 1e-9
#define inf 1000000000
#define infll 1000000000000000000LL
#define abs(x) ((x)<0?-(x):(x))
#define sqr(x) ((x)*(x))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(x) ((int)(x).size())
#define FORab(i,a,b) for (int i=(a); i<=(b); ++i)
#define RFORab(i,a,b) for (int i=(a); i>=(b); --i)
#define FOR1(i,n) FORab(i,1,(n))
#define RFOR1(i,n) RFORab(i,(n),1)
#define FOR(i,n) FORab(i,0,(n)-1)
#define RFOR(i,n) RFORab(i,(n)-1,0)
#define allstl(i,x,t) for (t::iterator i = (x).begin(); i!=(x).end(); ++i)
#define rallstl(i,x,t) for (t::reverse_iterator i = (x).rbegin(); i!=(x).rend(); ++i)
#define ms(a,v) memset(a,v,sizeof(a))
#define msn(a,v,n) memset(a,v,n*sizeof(a[0]))
#define mcp(d,s,n) memcpy(d,s,n*sizeof(s[0]))

template<class T> inline void checkmin(T &a,T b){if(b<a) a=b;}
template<class T> inline void checkmax(T &a,T b){if(b>a) a=b;}

int main()
{
    int n;
    int e1=0,e2=0,e3=0;
    freopen("input.txt","r",stdin);
    cin>>n;
    FOR(i,n)
    {
        int l,b;
        cin>>b>>l;
        if(i==0)
        {
            e1=l;
            e2=b;
            e3=b;
           // cout<<e1<<"\n";
            continue;
        }
        int t1=e1+l+max(abs((b-e2)),abs((b-e3)));
        int t2=e1+b+max(abs((l-e2)),abs((l-e3)));
        if(t1<t2)
        {
            e1=t2;
            e2=l;
            e3=e2;
        }
        else if(t1==t2)
        {
            e1=t1;
            e2=l;
            e3=b;
        }
        else
        {
            e1=t1;
            e2=b;
            e3=e2;
        }
       // cout<<e1<<"\n";
    }
    cout<<e1<<"\n";
    return 0;
}

但我仍然得到一个错误的答案,我不明白为什么我得到错误的答案..

2 个答案:

答案 0 :(得分:3)

你的错误回答很可能是因为贪婪的算法不正确(我很可能只是因为我没有反例,我确实认为它不正确)。

您可以使用动态编程。状态为(prefix_len, rotated),其中prefix_len是已处理的矩形数,rotated是bool值,表示最后一个矩形是否已旋转。每个州的价值是周长的最大长度。 基本情况是只有一个矩形的情况(很简单)。要计算其他状态的值,您可以从左到右迭代矩形,将它们置于旋转位置而不是旋转位置并选择最佳选项:从状态(prefix_len - 1, False)(prefix_len - 1, True)转换,取决于哪一个给出更长的周长 答案是max(f(n, False), f(n, True))

此算法使用O(n)时间和O(1)内存(因为您实际上只需要存储prefix_len - 1的值)。

答案 1 :(得分:1)

当您从左向右传递时,您当前的算法当前似乎会选择矩形i的方向,以最大化矩形0到i的上方包络的长度。但看看这个例子。如果只有一个矩形,那么最好的解决方案是将HKLM定向为顺时针方向。所以矩形的最佳方向不仅取决于其左边的矩形;它还取决于右边的矩形。

解决此问题的一种方法是通过动态编程。我们可以观察到矩形的最佳方向实际上仅取决于直接围绕它的两个矩形,因此我们只需要保持恒定的状态量。这是一些代码。

// The upper envelope of rectangles 0 through i - 1 given that we orient i - 1 horizontally
int envelopeHorizontal = 0;
// The upper envelope or rectangles 0 through i - 1 given that we orient i - 1 vertically
int envelopeVertical = 0;

int numRectangles;
std::cin >> numRectangles;

int prevShortSide = 0, prevLongSide = 0;
for (int i = 0; i < numRectangles; ++i) {
    int shortSide, longSide;
    std::cin >> shortSide >> longSide;

    if (i == 0) {
        envelopeHorizontal = longSide;
        envelopeVertical = shortSide;
    } else {
        const int newHorizontal = longSide
            + std::max(std::abs(prevLongSide - shortSide) + envelopeVertical,
                       std::abs(prevShortSide - shortSide) + envelopeHorizontal);
        const int newVertical = shortSide
            + std::max(std::abs(prevLongSide - longSide) + envelopeVertical,
                       std::abs(prevShortSide - longSide) + envelopeHorizontal);
        envelopeHorizontal = newHorizontal;
        envelopeVertical = newVertical;
    }
    prevShortSide = shortSide;
    prevLongSide = longSide;
}
std::cout << std::max(envelopeHorizontal, envelopeVertical) << "\n";

PS一旦你的代码正常运行,我强烈建议你将它提交给codereview.SE - 你似乎已经养成了一些习惯,这使你很难理解你的代码。