簡體   English   中英

C++:不知道如何解決坐標平面內比較坐標問題中的超時

[英]C++: I don't know how to solve the timeout in the problem of comparing coordinates in the coordinate plane

最多可輸入 100,000 個坐標。 只輸出對應特定條件的坐標。 如果存在x值比每個坐標大而y值小的坐標,則對應的坐標從輸出列表中排除。

我的英語不好,所以我舉了一些例子。

[輸入]首先輸入要輸入的坐標數N。 並輸入坐標。

[輸出]條件對應的坐標編號按升序輸出。

p2 不正確p4 正確

[input example]

6
1 3
6 6
7 3
8 2
8 6
2 1
[output example]

4
5
6

時間限制為 500 毫秒。

[timeout input example]

50000
1 1
1 2
1 3
... skip
1 49999
1 50000
[timeout output example]

1 1
1 2
1 3
... skip
1 49999
1 50000

坐標圖像:

圖片

下面的問題用一個簡單的循環就解決了,但是輸入100000個值就會超時。 我不知道該使用哪種算法。

我還附上了我寫的 C++ 源代碼。

另外,我試過用sort函數,但是當N的個數少時,效果很好,當N的個數很大時,就不能正常比較了。 我想我無法正確編寫比較函數。 所以我嘗試在不使用 sort 的情況下編寫源代碼。

想了兩天,改正了,還是沒解決,求幫助。 謝謝閱讀。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
    int N;
    cin >> N;
    bool* visible = new bool[N];
    for (int i = 0; i < N; i++)visible[i] = true;
    
    vector<pair<int,pair<int, int>>> v;
    
    for (int i = 0; i < N; i++) {
        int a, b;
        cin >> a >> b;
        v.push_back(make_pair(i,make_pair(a, b)));
    }

    for (int i = 0; i < v.size(); i++) {
        if (visible[i] == false)
            continue;
        for (int j = 0; j < v.size(); j++) {
            if (visible[i] == true &&visible[j]==true && v[i].second.first < v[j].second.first && v[i].second.second > v[j].second.second) {
                visible[i] = false;
                break;
            }
            else if (visible[i] == true && visible[j] == true && v[i].second.first > v[j].second.first && v[i].second.second < v[j].second.second) {
                visible[j] = false;
                continue;
            }
        }
    }
    for (int i = 0; i < v.size(); i++) {
        if (visible[i] == true)
            cout << v[i].first + 1 << endl;
    }
    return 0;
}

[試圖排序但失敗的源代碼]

#include <iostream>
#include <algorithm>
#include <vector>
#include <tuple>
using namespace std;
bool* visible;

int compare(pair<int, pair<int, int>> n1, pair<int, pair<int, int>> n2) {
    pair<int, int> a = n1.second, b = n2.second;
    bool swap = false;
    if (a.first > b.first && a.second < b.second) { 
        visible[n2.first - 1] = false;
        swap = true;
    }
    else if (a.first < b.first && a.second > b.second) {
        visible[n1.first - 1] = false;
        //swap = true;
    }

    cout << "[" << n1.first << "]" << a.first << ", " << a.second << " vb : " << visible[n1.first - 1] << " :\t[" << n2.first << "]" << b.first << ", " << b.second << "vb : " << visible[n2.first - 1] << "\t";
    cout << "swap: " << swap << endl;
    return swap;
}
int main() {
    int N;
    cin >> N;
    visible = new bool[N];
    for (int i = 0; i < N; i++)visible[i] = true;
    vector<pair<int, pair<int, int>>> v;

    for (int i = 0; i < N; i++) {
        int a, b;
        cin >> a >> b;
        v.push_back(make_pair(i+1, make_pair(a, b)));
    }
    sort(v.begin(), v.end(), compare);
    for (int i = 0; i < v.size(); i++)
        cout << "p" << v[i].first << " : " << v[i].second.first << ", " << v[i].second.second <<"\t"<< visible[v[i].first-1]<< endl;
    
    return 0;
}

在此處輸入圖片說明

在這種情況下,p4 移動到 (4,2)。 在這種情況下,p3,4,5,6 成為正確答案。

我不完全確定這適用於每個角落情況,但這個想法就在這里。 我花了一段時間才確定下來,可能是因為問題描述不是很清楚。 基本上,您希望將可以找到另一個具有較大 x 和較小 y 的點標記為不可見,即在其右下方有另一個點的點。

如果您在 x 上對您的點進行排序,那么您只需要檢查那些具有較大索引的點。

事實上,我們只對 y 最小的那個感興趣,因為它會支配所有其他的。

該值只能在從右向左移動時減小,因此我們只需要跟蹤最小值 y。 唯一的問題是如何處理具有相同 x 的點,因為它們可能在較高的 y 之前具有較低的 y,從而使有效點不可見 訣竅是確保從右到左瀏覽時(從高索引到低索引),y 會減小。 所以在排序時,如果 x 相等,我們將在 y 上排序。

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

int main() 
{
    struct point {
        int x, y;
        bool visible = true;
    };

    size_t N;
    std::cin >> N;
    std::vector<point> v(N);
    std::vector<size_t> idx(N);
    for (size_t i = 0; i < N; ++i) {
        auto& p = v[i];
        idx[i] = i;
        std::cin >> p.x >> p.y;
    }

    sort(idx.begin(), idx.end(), [&v](const size_t& a, const size_t& b) { 
        if (v[a].x == v[b].x)
            return v[a].y < v[b].y;
        return v[a].x < v[b].x; 
    });

    int miny = INT_MAX;
    for (size_t i = N; i-- > 0;) {
        auto& p = v[idx[i]];
        miny = std::min(miny, p.y);
        if (p.y > miny) {
            p.visible = false;
        }
    }

    for (size_t i = 0; i < N; ++i) {
        auto& p = v[i];
        if (p.visible) {
            std::cout << i + 1 << '\n';
        }
    }

    return 0;
}

我從您的代碼中了解到兩件事,因此我將列出兩個解決方案:

I:這是修改后的“最長遞增子序列”的基本示例。

讓我們首先將坐標視為不同的東西,比方說,坐標 (x,y) 將成為具有高度 (x) 和寬度 (y) 的 ractangle(考慮這就像我們正在制作帶有角 (0,0) 的矩形) (x,0) (0,y) (x,y))。

如果我們需要“上升”點,則意味着它們的區域重疊。 更正式地說,如果我們需要的點列表是 A(1),A(2),A(3),...,A(k),那么對於范圍 1..k-1 中的每個 i,A( i).x<A(i+1).x 和 A(i).y<A(i+1).y。

您可以使用找到最佳解決方案

注意:坐標應該排序。 根據什么標准? 好吧,只要在對該標准進行排序之后出現最長的遞增子序列,那么它就是正確的。

II:這是找到凸包的基本示例。

多邊形的凸包將是凸多邊形(具有最多節點),其坐標集包含在原始多邊形的坐標集中。 我建議閱讀此內容 找到上半部分后,你可以應用前面例子中描述的思路,盡管你必須找到一個子串而不是一個子序列,這樣會使復雜度 O(nlog+n)

希望這有幫助

給定兩點 A 和 B,有三種可能的配置:

  1. A 使 B 不可見
  2. B 使 A 不可見
  3. 以上都不是

點之間的“不可見”關系不是std::sort要求的嚴格弱std::sort ,因此使用實現此關系的比較函數調用std::sort是未定義的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM