牛客假日团队赛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) 深刻理解函数(上)
