牛客假日团队赛5J护城河 bzoj 1670: [Usaco2006 Oct]Building the Moat护城河的挖掘 (凸包的周长)...
鏈接:https://ac.nowcoder.com/acm/contest/984/J
來源:牛客網
護城河
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld
題目描述
為了防止口渴的食蟻獸進入他的農場,Farmer John決定在他的農場周圍挖一條護城河。農場里一共有N(8<=N<=5,000)股泉水,并且,護城河總是筆直地連接在河道上的相鄰的兩股泉水。護城河必須能保護所有的泉水,也就是說,能包圍所有的泉水。泉水一定在護城河的內部,或者恰好在河道上。當然,護城河構成一個封閉的環。
挖護城河是一項昂貴的工程,于是,節約的FJ希望護城河的總長度盡量小。請你寫個程序計算一下,在滿足需求的條件下,護城河的總長最小是多少。
所有泉水的坐標都在范圍為(1..10,000,000,1..10,000,000)的整點上,一股泉水對應著一個唯一確定的坐標。并且,任意三股泉水都不在一條直線上。
以下是一幅包含20股泉水的地圖,泉水用""表示:
...-----------------......
../.......................
./.........................
.........................
|........................
|.........................
|..........................
..........................|
.*........................|
.........................|
........................|
.........................
......................./.
......................../..
.......----------------...
(請復制到記事本中用等寬字體查看)
圖中的直線,為護城河的最優挖掘方案,即能圍住所有泉水的最短路線。
路線從左上角起,經過泉水的坐標依次是:(18,0),(6,-6),(0,-5),(-3,-3),(-17,0),(-7,7),(0,4),(3,3)。繞行一周的路徑總長為70.8700576850888(...)。答案只需要保留兩位小數,于是輸出是70.87。
輸入描述:
第1行: 一個整數,N
第2..N+1行: 每行包含2個用空格隔開的整數,x[i]和y[i],即第i股泉水的位置坐標
輸出描述:
第1行: 輸出一個數字,表示滿足條件的護城河的最短長度。保留兩位小數
示例1
輸入
復制
20
2 10
3 7
22 15
12 11
20 3
28 9
1 12
9 3
14 14
25 6
8 1
25 1
28 4
24 12
4 15
13 5
26 5
21 11
24 4
1 8
輸出
復制
70.87
思路:
模板題,直接看代碼吧。
細節見代碼:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define rt return #define dll(x) scanf("%I64d",&x) #define xll(x) printf("%I64d\n",x) #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;} inline void getInt(int* p); const int maxn = 1000010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/const int MAX=5005;// 最大點數 const int INF=0x3f3f3f3f;//坐標的最大值 // 本模板讀入默認是1-n讀入 int n; int top; struct Node {int x,y; }p[MAX],S[MAX];//p儲存節點的位置,S是凸包的棧 inline bool cmp(Node a,Node b)//比較函數,對點的極角進行排序 {double A=atan2((a.y-p[1].y),(a.x-p[1].x));double B=atan2((b.y-p[1].y),(b.x-p[1].x));if(A!=B)return A<B;else return a.x<b.x; //這里注意一下,如果極角相同,優先放x坐標更小的點 } long long Cross(Node a,Node b,Node c)//計算叉積 {return 1LL*(b.x-a.x)*(c.y-a.y)-1LL*(b.y-a.y)*(c.x-a.x); } void Get()//求出凸包 {p[0]=(Node){INF,INF};int k;for(int i=1;i<=n;++i)//找到最靠近左下的點if(p[0].y>p[i].y||(p[0].y==p[i].y&&p[i].x<p[0].x)){p[0]=p[i];k=i;}swap(p[k],p[1]);sort(&p[2],&p[n+1],cmp);//對于剩余點按照極角進行排序S[0]=p[1],S[1]=p[2];top=1;//提前在棧中放入節點for(int i=3;i<=n;)//枚舉其他節點{if(top&&Cross(S[top-1],p[i],S[top])>=0)top--;//如果當前棧頂不是凸包上的節點則彈出else S[++top]=p[i++];//加入凸包的棧中}//底下這個玩意用來輸出凸包上點的坐標//for(int i=0;i<=top;++i)// printf("(%d,%d)\n",S[i].x,S[i].y); } double getdis(Node one ,Node two) {double res=sqrt((one.x-two.x)*(one.x-two.x)+(two.y-one.y)*(two.y-one.y));return res;} double solve()// 返回凸包的邊長 ___注意n=1,n=2時候的特判 {double ans=0.00000000000000;ans=ans+getdis(S[0],S[top]);repd(i,1,top){ans=ans+getdis(S[i],S[i-1]);}return ans; }int main() {//freopen("D:\\code\\text\\input.txt","r",stdin);//freopen("D:\\code\\text\\output.txt","w",stdout);gbtb;cin>>n;repd(i,1,n){cin>>p[i].x>>p[i].y;}Get();cout<<fixed<<setprecision(2)<<solve()<<endl;return 0; }inline void getInt(int* p) {char ch;do {ch = getchar();} while (ch == ' ' || ch == '\n');if (ch == '-') {*p = -(getchar() - '0');while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 - ch + '0';}}else {*p = ch - '0';while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 + ch - '0';}} }轉載于:https://www.cnblogs.com/qieqiemin/p/11284425.html
總結
以上是生活随笔為你收集整理的牛客假日团队赛5J护城河 bzoj 1670: [Usaco2006 Oct]Building the Moat护城河的挖掘 (凸包的周长)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: struct linger
- 下一篇: F#学习之路(2) 深刻理解函数(上)