利用分治策略解題
今天封神講分治和倍增,分治還是比較神奇的一種思想的,能解決不少問題,思路就是把一個大問題劃分成小問題,然後通過遞迴求解小問題,最終得到大問題的解。
- 歸併排序
歸併排序是分治的一個典型應用,具體實現就是把一個長序列不斷二分,分成的兩部分比較大小後再合併到一個新的陣列,最終得到排序後的結果。
歸併排序除了可以排序,還可以求逆序對,個人覺得比用樹狀陣列要好想一些。
POJ2299
裸的求逆序對,方法是每次合併前後兩個序列時,如果後面的陣列要先於前面的插入,則這個數和前面的每一個數都構成一個逆序對。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=500000+10;
int n;
long long a[maxn],tmp[maxn],ans;
void merge(int l,int m,int r){
int i=l,j=m+1,k=l;
while(i<=m&&j<=r){
if(a[i]>a[j]){
tmp[k++]=a[j++];
ans+=m-i+1;
}
else{
tmp[k++]=a[i++];
}
}
while(i<=m) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for(int p=l;p<=r;p++){
a[p]=tmp[p];
}
}
void merge_sort(int l,int r){
if(l<r){
int mid=(l+r)/2;
merge_sort(l,mid);
merge_sort(mid+1,r);
merge(l,mid,r);
}
}
int main(){
while(scanf("%d",&n)){
if(n==0) break;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
ans=0;
merge_sort(1,n);
printf("%lld\n",ans);
}
return 0;
}
- 平面上的最近點對
這個貌似是個很洋氣的題啊,資料範圍很大,考慮分治策略。
將平面的點按x座標排序,然後將區間(l,r)分為(l,mid)和(mid+1,r),分別遞迴求解左右兩個區間的最短距離,還有一種情況,兩個點橫跨兩個區間,這樣的點需要特殊處理。
處理也挺麻煩的,詳見程式碼。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <iomanip>
#include<cmath>
using namespace std;
const int maxn=200000+10;
const double INF=1e100;
int n;
double ans;
struct node{
long long x,y;
int set;
}p[maxn];
int t[maxn];
int cmp(node a,node b){
if(a.x!=b.x) return a.x<b.x;
else return a.y<b.y;
}
int cmp2(int a,int b){
return p[a].y<p[b].y;
}
double dist(int x,int y){
if(p[x].set==p[y].set) return INF;
double ans2= sqrt((p[x].x-p[y].x)*(p[x].x-p[y].x) + (p[x].y-p[y].y)*(p[x].y-p[y].y));
return ans2;
}
double work(int l,int r){
if(l==r) return INF;
if(l==r-1) return dist(l,r);
int m=(l+r)/2;
double minl=work(l,m);
double minr=work(m+1,r);
double minlr=min(minl,minr);
int k=0;
for(int i=l;i<=r;i++){
if(p[i].x-p[i+1].x<=minlr){
k++;
t[k]=i;
}
}
sort(t+1,t+k+1,cmp2);
for(int i=1;i<=k;i++){
for(int j=i+1;j<=k;j++){
if(p[t[i]].y-p[t[j]].y >=minlr|| p[t[i]].set==p[t[j]].set) break;
minlr=min(minlr,dist(t[i],t[j]));
}
}
return minlr;
}
int main(){
int T;
scanf("%d",&T);
for(int c=1;c<=T;c++){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&p[i].x,&p[i].y);
p[i].set=1;
}
for(int i=n+1;i<=2*n;i++){
scanf("%lld%lld",&p[i].x,&p[i].y);
p[i].set=2;
}
n*=2;
sort(p+1,p+n+1,cmp);
ans=work(1,n);
//printf("%.3lf\n",ans);
cout<<setiosflags(ios::fixed)<<setprecision(3)<<ans<<endl;
}
return 0;
}
helenkeller
2016.7.3
相關文章
- 分治思想--快速排序解決TopK問題排序TopK
- 線段樹分治略解&雜題解析
- 讀人工智慧全傳03分治策略人工智慧
- 樹分治 - 點分治
- 演算法導論_第四章_分治策略演算法
- 分治演算法-眾數問題演算法
- 分治
- 利用errorstack event解決問題Error
- Note - 樹分治(點分治、點分樹)
- CDQ分治
- 分治法
- 分治合集
- 點分治
- 【題解】Solution Set - NOIP2024集訓Day14 CDQ分治
- 計算機演算法設計與分析——遞迴與分治策略(一)計算機演算法遞迴
- 分治演算法-求解棋盤覆蓋問題演算法
- 分治—快速排序排序
- 根號分治
- 量化策略:如何利用死貓反彈獲利?
- XAI有什麼用?探索LLM時代利用可解釋性的10種策略AI
- 分治FFT小記?FFT
- 分治演算法演算法
- 靜態點分治
- D-CDQ分治
- 演算法:利用分治演算法求解N個元素中的第M大元素演算法
- 程式設計師解決問題的 60 個策略程式設計師
- 程式設計師解決問題的60個策略程式設計師
- APP線下推廣常見問題及解決策略APP
- 利用PCT解決快速重新整理效能問題
- 詳解分散式系統本質:“分治”和“冗餘”分散式
- 如何利用策略模式優化表單驗證模式優化
- 利用策略模式優化過多 if else 程式碼模式優化
- 利用LRU策略實現Axios請求快取iOS快取
- 當prompt策略遇上分治演算法,南加大、微軟讓大模型煉成「火眼金睛」演算法微軟大模型
- 同源策略詳解
- 【2024-ZR-C Day 5】資料結構(3):莫隊(帶修莫隊、回滾莫隊)、邊分治、點分治、樹分治、動態點分治資料結構
- 過多if - else 的問題, 以及策略模式 + 反射解決方法模式反射
- 深入跨域問題(2) - 利用 CORS 解決跨域跨域CORS