[School Regional Team Contest, Saratov, 2011] - J. Minimum Sum (分治,幾何)
阿新 • • 發佈:2020-10-28
[School Regional Team Contest, Saratov, 2011] - J. Minimum Sum (分治,幾何)
題面:
題意:
在二維平面上給定\(\mathit n\)個向量,對於每一個向量,你可以使用對應的操作使其座標變為相反數,現在讓你選擇兩個向量\(v_i,v_j\)和其對應的操作\(k_1,k_2\),使其$|v_i^{k_1} +v_j^{k_2} | $ 最小。如果有多種方案,請輸出任意一個。
思路:
通過觀察四種操作,即可以對向量進行對座標軸對稱,和對原點對稱。
那麼我們將其問題先轉化為$|v_i^{k_1} -v_j^{k_2} | $ (只要變化一下\(k_2\or k_1\)
通過幾何知識分析可得:$|v_i^{k_1} -v_j^{k_2} | $ ,就是向量\(v_i^{k_1} ,v_j^{k_2} \)的座標表示法時對應的二維平面點的距離。
那麼我們將所有點(將向量的起點平移到原點對應的端點。)轉到第一象限,
然後用分治法求二維平面點的最短距離,同時維護出最短距離點對對應的向量資訊,在輸出時將一個\(\mathit k\) 轉一下即可。
程式碼:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; int MAX = 1e9; //定義的最大距離,以在只有一個點的時返回無窮大 int a, b; //用來記錄下標,與題無關 struct Node { int x, y; int key; //關鍵碼,可有可無,與ab有關 int type; }; Node ar[100005], br[100005]; bool cmpx(Node a, Node b) {return a.x < b.x;} //x座標升序 bool cmpy(Node a, Node b) {return a.y < b.y;} //y座標升序 int min(int a, int b) {return a < b ? a : b;} //返回最小值 int dis(Node a, Node b) {return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);} //返回點與點之間的距離 int ans1, ans2, ans3, ans4; int ans_dis = 1e9; int cal(int s, int e) //s、e用來表示當前處理的陣列中的下標位置 { int mid, i, j, tail = 0; //mid表示陣列中間的位置下標 ,tail作為計數變數,是用來br陣列儲存標號的 int d; //d表示點對之間的距離 if (s == e) { return MAX; } //如果只有一個點 mid = (s + e) / 2; d = min(cal(s, mid), cal(mid + 1, e)); //遞迴求出左右兩邊的最小距離 //下面是求是否存在左邊的點到右邊某點的距離小於d的點,或者是否存在在右邊的點到左邊某點的距離小於d的點,若是存在,必定處於一個d*2d的矩形中 for (i = mid; i >= s && (ar[mid].x - ar[i].x) * (ar[mid].x - ar[i].x) < d; i--) { //篩選左邊的點,在中間位置左側d以內的點 br[tail++] = ar[i]; } for (i = mid + 1; i < e && (ar[i].x - ar[mid].x) * (ar[i].x - ar[mid].x) < d; i++) { //同上,篩選右邊的點 br[tail++] = ar[i]; } sort(br, br + tail, cmpy);// sort for y for (i = 0; i < tail; i++) {//列舉矩形內點對之間的距離 for (j = i + 1; j < tail && (br[j].y - br[i].y) * (br[j].y - br[i].y) < d; j++) { if (d > dis(br[i], br[j])) { //更新點的值 d = min(d, dis(br[i], br[j])); if (d < ans_dis) { ans_dis = d; ans1 = br[i].key; ans2 = br[i].type; ans3 = br[j].key; ans4 = br[j].type; } } } } return d; //返回最小的點對之間的距離 } int main() { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int n; cin >> n; for (int i = 0; i < n; i++) { ar[i].key = i + 1; //關鍵碼賦值 scanf("%d %d", &ar[i].x, &ar[i].y); if (ar[i].x >= 0 && ar[i].y >= 0) { ar[i].type = 1; } else if (ar[i].x < 0 && ar[i].y >= 0) { ar[i].type = 2; } else if (ar[i].x >= 0 && ar[i].y < 0) { ar[i].type = 3; } else if (ar[i].x < 0 && ar[i].y < 0) { ar[i].type = 4; } ar[i].x = abs(ar[i].x); ar[i].y = abs(ar[i].y); } sort(ar, ar + n, cmpx); //按x對ar排序 int d = cal(0, n); if (ans4 == 2) { ans4 = 3; } else if (ans4 == 3) { ans4 = 2; } else if (ans4 == 1) { ans4 = 4; } else { ans4 = 1; } printf("%d %d %d %d\n", ans1, ans2, ans3, ans4 ); return 0; }