2013資料結構課程設計之便利店選址(暴力列舉或隨機函式或三分)
[問題描述]
某小區決定在小區內部建一家便利店,現小區內部共有八棟樓,它們的地理座標分別為:(10,20) (30,34) (19,25) (38,49.1) (9,38.1) (2,34) (5,8) (29,48)。同時,其中的住戶人數分別為:30, 45, 28, 8, 36, 16, 78, 56。為了方便更多的住戶購物,要求實現總體最優,請問便利店應該建立在哪裡?
【提示】
1)便利店無論選址何處,八棟樓的居民均可直接到達,即八棟樓與便利店均相鄰,且距離為直線距離;
2)八棟樓的居民人數為權重,應該方便大多數人,實現總體最優。
先是暴力找點的方法。
解題思路:自己開始想的就是暴力列舉,先找大範圍,再找小範圍。做這個題目就想到了的warmup2的1002題,但當時就是A不了。思路很簡單,一步步地精確範圍。先把整個地方劃分成10*10的方格,再在裡面找哪個最小,然後繼續10*10每次都這樣劃分,精度確定跳出迴圈即可。詳解見程式碼。
程式碼:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<ctime>
using namespace std;
int n; //n棟樓
double minx,miny,maxx,maxy,px,py; //找到四個邊界
double ansx,ansy,sum; //最後的結果
struct mq
{
double x;
double y;
int peo;
};
mq node[1005];
double cal(double px,double py) //計算值
{
int i;
double sum=0;
for(i=0;i<n;i++)
sum+=sqrt((px-node[i].x)*(px-node[i].x)+(py-node[i].y)*(py-node[i].y))*node[i].peo;
return sum;
}
void solve()
{
double i,j;
double fenx=maxx-minx; //把x分成若干份
double feny=maxy-miny; //把y分成若干份
while(fenx>0.01&&feny>0.01) //暴力找點
{
fenx/=10.0,feny/=10.0;
for(i=minx;i<=maxx;i+=fenx)
for(j=miny;j<=maxy;j+=feny)
{
double tmp=cal(i,j);
if(tmp<sum)
{
sum=tmp;
ansx=i;
ansy=j;
}
}
minx=ansx-fenx;
miny=ansy-feny;
maxx=ansx+fenx;
maxy=ansy+feny;
}
}
int main()
{
int i;
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
while(~scanf("%d",&n)) //n棟樓
{
scanf("%lf%lf%d",&node[0].x,&node[0].y,&node[0].peo);
minx=maxx=node[0].x; miny=maxy=node[0].y;
//找到四個邊界
for(i=1;i<n;i++)
{
scanf("%lf%lf%d",&node[i].x,&node[i].y,&node[i].peo);
if(node[i].x<minx) minx=node[i].x;
if(node[i].x>maxx) maxx=node[i].x;
if(node[i].y<miny) miny=node[i].y;
if(node[i].y>maxy) maxy=node[i].y;
}
sum=100000000;
solve();
cout<<"便利店選址座標為:"<<endl;
cout<<"x: "<<ansx<<" "<<"y: "<<ansy<<endl;
cout<<"最優解為: "<<sum<<endl;
}
return 0;
}
/*
8
10 20 30
30 34 45
19 25 28
38 49.1 8
9 38.1 36
2 34 16
5 8 78
29 48 56
便利店選址座標為:
x: 16.5404 y: 27.4362
最優解為: 5146.85
*/
然後就是LCM說的隨機演算法,也沒想到那一塊,被他一說是有些道理,但是點的範圍一擴大的話,就沒那麼準確了。
隨機演算法,我是直接採用的隨機數然後%lenth,區間寬度,相當於0~lenth-1。隨機函式對範圍要求比較嚴格吧,範圍如果太大,隨機也沒用了。具體實現見程式碼:
程式碼:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<ctime>
using namespace std;
int n; //n棟樓
struct mq
{
double x;
double y;
int peo;
};
mq node[1005];
double cal(double px,double py) //計算值
{
int i;
double sum=0;
for(i=0;i<n;i++)
sum+=sqrt((px-node[i].x)*(px-node[i].x)+(py-node[i].y)*(py-node[i].y))*node[i].peo;
return sum;
}
int main()
{
int i;
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
double minx,miny,maxx,maxy,px,py; //找到四個邊界
double ansx,ansy; //最後的結果
while(~scanf("%d",&n)) //n棟樓
{
scanf("%lf%lf%d",&node[0].x,&node[0].y,&node[0].peo);
minx=maxx=node[0].x; miny=maxy=node[0].y;
//找到四個邊界
for(i=1;i<n;i++)
{
scanf("%lf%lf%d",&node[i].x,&node[i].y,&node[i].peo);
if(node[i].x<minx) minx=node[i].x;
if(node[i].x>maxx) maxx=node[i].x;
if(node[i].y<miny) miny=node[i].y;
if(node[i].y>maxy) maxy=node[i].y;
}
minx*=100,maxx*=100,miny*=100,maxy*=100; //邊界擴大一百倍
//找到邊界了就可以隨機了
int lenx,leny;
lenx=ceil(maxx-minx),leny=ceil(maxy-miny);
double sum=1000000000;
srand((unsigned)time(NULL)); //播種
for(i=1;i<=500000;i++) //隨機50W次
{
px=rand()%lenx+minx;
py=rand()%leny+miny;
px/=100.0;
py/=100.0;
double tmp=cal(px,py);
if(tmp<sum)
{
sum=tmp;
ansx=px;
ansy=py;
}
}
cout<<"便利店選址座標為:"<<endl;
cout<<"x: "<<ansx<<" "<<"y: "<<ansy<<endl;
cout<<"最優解為: "<<sum<<endl;
}
return 0;
}
/*
8
10 20 30
30 34 45
19 25 28
38 49.1 8
9 38.1 36
2 34 16
5 8 78
29 48 56
便利店選址座標為:
x: 16.56 y: 27.44
最優解為: 5146.85
*/
然後是gcz在我們班群裡面說的三分的方法,這個三分很久都沒寫過了,這個也是二維的三分。二分是解決單調性不變的函式,而三分則是解決類似拋物線這樣的函式,有一個凸點或凹點。後來問了一下同學,思路是這樣,先三分x,在三分x的基礎上再三分y在y裡面找一個滿足條件的最小的一個,大題思路是這樣,具體實現見程式碼。
程式碼:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<ctime>
using namespace std;
int n; //n棟樓
double minx,miny,maxx,maxy; //找到四個邊界
double ansx,ansy,sum; //最後的結果
double midy; //便於最後輸出
double eps=0.001;
struct mq
{
double x;
double y;
int peo;
};
mq node[1005];
double dis(double px,double py) //算sum值
{
int i;
double sum=0;
for(i=0;i<n;i++)
sum+=sqrt((px-node[i].x)*(px-node[i].x)+(py-node[i].y)*(py-node[i].y))*node[i].peo;
return sum;
}
double cal(double x) //每次返回x確定三分y使得dis(x,y)最小的x,y.
{
double lefty,righty,mimidy;
lefty=miny,righty=maxy;
while(righty-lefty>eps)
{
midy=(lefty+righty)/2.0,mimidy=(righty+midy)/2.0;
if(dis(x,midy)<dis(x,mimidy))
righty=mimidy;
else
lefty=midy;
}
return dis(x,midy);
}
int main()
{
int i;
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
while(~scanf("%d",&n)) //n棟樓
{
scanf("%lf%lf%d",&node[0].x,&node[0].y,&node[0].peo);
minx=maxx=node[0].x; miny=maxy=node[0].y;
for(i=1;i<n;i++) //找到四個邊界
{
scanf("%lf%lf%d",&node[i].x,&node[i].y,&node[i].peo);
if(node[i].x<minx) minx=node[i].x;
if(node[i].x>maxx) maxx=node[i].x;
if(node[i].y<miny) miny=node[i].y;
if(node[i].y>maxy) maxy=node[i].y;
}
double leftx,rightx,midx,mimidx;
leftx=minx,rightx=maxx;
while(rightx-leftx>eps) //三分x的基礎上三分y,找到最小的.感謝小雨,gcz
{
midx=(leftx+rightx)/2.0,mimidx=(rightx+midx)/2.0;
if(cal(midx)<cal(mimidx))
rightx=mimidx;
else
leftx=midx;
}
ansx=midx,ansy=midy;
sum=dis(ansx,ansy);
cout<<"便利店選址座標為:"<<endl;
cout<<"x: "<<ansx<<" "<<"y: "<<ansy<<endl;
cout<<"最優解為: "<<sum<<endl;
}
return 0;
}
/*
8
10 20 30
30 34 45
19 25 28
38 49.1 8
9 38.1 36
2 34 16
5 8 78
29 48 56
便利店選址座標為:
x: 16.5389 y: 27.4345
最優解為: 5146.85
*/
相關文章
- 資料庫建模或表結構(模型設計)_隨記(二)資料庫模型
- 專案組織結構設計或選擇(轉)
- 資料結構課程設計-宿舍管理系統資料結構
- 資料模型設計(表結構)之隨記模型
- 2013資料結構課程設計之通訊錄(複習連結串列與檔案知識)資料結構
- 資料結構課程設計報告——暢通工程資料結構
- 類中的結構體或列舉等型別的前置宣告結構體型別
- 資料結構課程設計——學生資訊管理系統資料結構
- USB裝置的列舉過程分析——資料結構先行資料結構
- [Java] 隨機返回1或0的表示式Java隨機
- 資料庫課程設計資料庫
- 資料結構 課程設計 員工管理系統(C語言)資料結構C語言
- OCP課程23:管理Ⅰ之資料庫體系結構資料庫
- 列舉python常用的資料結構Python資料結構
- 航班資訊查詢和檢索系統-資料結構課程設計資料結構
- mysqldump只匯入資料或只導結構MySql
- 資料結構之「佇列」資料結構佇列
- 資料結構之「陣列」資料結構陣列
- 資料結構之陣列資料結構陣列
- 慕課網玩轉資料結構課程之陣列資料結構陣列
- JavaScript資料結構之連結串列--設計JavaScript資料結構
- 使用列舉ENUM替換Switch或If-Else
- matlab產生隨機數或隨機矩陣Matlab隨機矩陣
- JavaScript資料結構之-佇列JavaScript資料結構佇列
- 資料結構之佇列(Queue)資料結構佇列
- JavaScript資料結構之佇列JavaScript資料結構佇列
- OCP課程6:SQL之使用組函式SQL函式
- Java 程式設計技巧之資料結構Java程式設計資料結構
- 【matlab程式設計】matlab隨機數函式Matlab程式設計隨機函式
- [課程複習] 資料結構之經典題目回顧 (一)選擇題、填空題1資料結構
- 結構、位域、聯合、列舉之小小總結
- awk之隨機函式rand()和srand()隨機函式
- 資料結構複習-01enum列舉型別資料結構型別
- JavaScript資料結構之陣列棧佇列JavaScript資料結構陣列佇列
- 重學資料結構之佇列資料結構佇列
- 資料結構之「雙端佇列」資料結構佇列
- 資料結構學習之佇列資料結構佇列
- 玩轉資料結構之陣列資料結構陣列