hdu6365 2018 Multi-University Training Contest 6 1004 Shoot Game
阿新 • • 發佈:2018-09-06
ont 區間 永遠 線段 scan for 分割 unique scanf
http://acm.hdu.edu.cn/showproblem.php?pid=6365
細節處理
- unique返回的是最後一位的後一位,因此從1開始的數組要減去(p+1)
- 結構體可以用unqiue和lower_bound,因此結構體也可以離散化
- 此處的斜率是x/y,因為這樣定義斜率會隨著x的增大而增大
思路
- 一開始見到這道題,因為是個計算幾何題,但是轉換的思路十分巧妙:
- 首先如何處理一條線段,假設我們穿過所有點的兩個端點,一定可以穿過所有線段,所以每條線段轉化為兩個點
- 那麽如何處理每個點(x,y),因為假如斜率相同的點,都能被一條射線穿過,因此實際上衡量每個點的標準應該是他的斜率,因此將每個點轉化為他的斜率
- 根據斜率將點排序,以兩點之間為區間進行區間dp,每次找區間內價值最大的一條線進行區間的分割,這樣只有完全包含在枚舉區間內的直線才能有貢獻(即假如在穿過當前直線時同時穿過的其他直線永遠也不會有貢獻了)
定義dp[i][j]為穿過包含在(i,j)區間所有直線所需要的最小代價(即穿過(i,j)區間但並不在i,j區間內的直線可能會被穿過,但是貢獻在之前已經被計算了)
轉移方程為dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+w[k]);
#include<bits/stdc++.h> #define M 305 #define ll long long #define inf 1e16 using namespace std; int n,i,T,sz; ll h[M<<1],w[M<<1],l[M<<1],r[M<<1],dp[M<<1][M<<1]; struct N{ ll x,y; N(){} N(ll x,ll y): x(x),y(y){} bool operator ==(const N& rhp)const{ return x*rhp.y-y*rhp.x==0; } bool operator<(const N& rhp)const{ return x*rhp.y-y*rhp.x<0; } }p[M<<1]; int id(N a){ return lower_bound(p+1,p+1+sz,a)-p;} ll dfs(int L,int R){ ll &ans=dp[L][R]; if(L>R)return 0; if(ans!=-1)return ans; ans=0; ll ma=-1,x; for(int i=1;i<=n;i++){ if(L<=l[i]&&r[i]<=R){ if(w[i]>ma){ ma=w[i];x=i; } } } if(ma==-1)return ans; ans=inf; for(int i=l[x];i<=r[x];i++){ ans=min(ans,dfs(L,i-1)+dfs(i+1,R)+ma); } return ans; } int main(){ scanf("%d",&T); while(T--){ memset(dp,-1,sizeof(dp)); scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%lld%lld%lld%lld",&h[i],&l[i],&r[i],&w[i]); p[2*i-1]=N(l[i],h[i]); p[2*i]=N(r[i],h[i]); } sort(p+1,p+1+2*n); sz=unique(p+1,p+2*n+1)-p-1; for(i=1;i<=n;i++){ l[i]=id(N(l[i],h[i])); r[i]=id(N(r[i],h[i])); } printf("%lld\n",dfs(1,sz)); } }
hdu6365 2018 Multi-University Training Contest 6 1004 Shoot Game