[学习笔记] [JSOI2018] luogu P4557 战争 - 闵可夫斯基和 - 凸包 - 计算几何 - 学习笔记

闵可夫斯基和即,两个凸包按照边的斜率从小到大加入即可。
本题中 ∃ b + Δ ⊆ A ⇒ ∃ b , Δ ⊆ A − b ⇒ Δ ⊆ { a − b ∣ a ∈ A , b ∈ B } \exist b+\Delta\subseteq A\Rightarrow\exist b,\Delta\subseteq A-b\Rightarrow\Delta\subseteq\{a-b|a\in A,b\in B\} b+ΔAb,ΔAbΔ{abaA,bB}

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x=0,ch,s=1;while(((ch=gc)<'0'||ch>'9')&&ch!='-');
    if(ch^'-') x=ch^'0';else s=-1;
    while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');
    return s>0?x:-x;
}
const int N=100010;
struct P{
    int x,y;P(int _x=0,int _y=0) { x=_x,y=_y; }
    inline int input() { return x=inn(),y=inn(); }
    inline bool operator<(const P &p)const { return x==p.x?y<p.y:x<p.x; }
    inline P operator+(const P &p)const { return P(x+p.x,y+p.y); }
    inline P operator-(const P &p)const { return P(x-p.x,y-p.y); }
    inline bool operator==(const P &p)const { return x==p.x&&y==p.y; }
    inline lint len2()const { return (lint)x*x+(lint)y*y; }
};typedef vector<P> poly;poly A,B,q;
inline lint cross(const P &a,const P &b) { return (lint)a.x*b.y-(lint)a.y*b.x; }
inline lint cross(const P &s,const P &t1,const P &t2) { return cross(t1-s,t2-s); }
inline poly convexHull(poly ps,int nedsort=1)
{
    int n=(int)ps.size();if(n<=2) return ps;
    if(nedsort) sort(ps.begin(),ps.end());
    poly ans(n<<1);int k=0;
    for(int i=0;i<n;ans[k++]=ps[i++])
        while(k>1&&cross(ans[k-2],ans[k-1],ps[i])<=0) k--;
    for(int i=n-1,t=k;i>=0;ans[k++]=ps[i--])
        while(k>t&&cross(ans[k-2],ans[k-1],ps[i])<=0) k--;
    return ans.resize(k-1),ans;
}
inline poly minkowskiSum(poly A,poly B)
{
    poly ans,vA,vB;vA.clear(),vB.clear();
    int n=(int)A.size(),m=(int)B.size();
    ans.resize(n+m+1);
    Rep(i,A) vA.pb(A[(i+1)%n]-A[i]);
    Rep(i,B) vB.pb(B[(i+1)%m]-B[i]);
    ans[0]=A[0]+B[0];int i=0,j=0,k=1;
    while(i<n&&j<m)
        if(cross(vA[i],vB[j])>=0) ans[k]=ans[k-1]+vA[i++],k++;
        else ans[k]=ans[k-1]+vB[j++],k++;
    while(i<n) ans[k]=ans[k-1]+vA[i++],k++;
    while(j<m) ans[k]=ans[k-1]+vB[j++],k++;
    return convexHull(ans);
}
inline int incmp(const P &p1,const P &p2)
{
    lint k=cross(p1,p2);if(k) return k>0;
    return p1.len2()<=p2.len2();
}
inline int inconvex(P p,const poly &ps)
{
    int n=(int)ps.size();if(p==ps[n-1]) return 1;
    if(!incmp(p,ps[n-1])) return 0;
    int x=lower_bound(ps.begin(),ps.end(),p,incmp)-ps.begin()-1;
    return cross(p-ps[x],ps[x+1]-ps[x])<=0;
}
int main()
{
    A.resize(inn()),B.resize(inn());int q=inn();
    Rep(i,A) A[i].input();
    Rep(i,B) B[i].input(),B[i].x=-B[i].x,B[i].y=-B[i].y;
    A=convexHull(A),B=convexHull(B);
    A=minkowskiSum(A,B);P bas=A[0];
    Rep(i,A) A[i]=A[i]-bas;P p;
    rep(i,1,q) p.input(),printf("%d\n",inconvex(p-bas,A));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用[1],dp[u][j]表示在u子树中选取恰好j个人时能获得的最大价值。而根据引用,该问题的时间复杂度为O(log2​104×nm)。 对于洛谷P2143 [JSOI2010] 巨额奖金问题,我们可以使用动态规划来解决。具体步骤如下: 1. 首先,我们需要构建一棵树来表示员工之间的关系。树的根节点表示公司的总经理,其他节点表示员工。每个节点都有一个权值,表示该员工的奖金金额。 2. 接下来,我们可以使用动态规划来计算每个节点的dp值。对于每个节点u,我们可以考虑两种情况: - 如果选择节点u,则dp[u][j] = dp[v][j-1] + value[u],其中v是u的子节点,value[u]表示节点u的奖金金额。 - 如果不选择节点u,则dp[u][j] = max(dp[v][j]),其中v是u的子节点。 3. 最后,我们可以通过遍历树的所有节点,计算出dp[u][j]的最大值,即为所求的巨额奖金。 下面是一个示例代码,演示了如何使用动态规划来解决洛谷P2143 [JSOI2010] 巨额奖金问题: ```python # 构建树的数据结构 class Node: def __init__(self, value): self.value = value self.children = [] # 动态规划求解最大奖金 def max_bonus(root, j): dp = [[0] * (j+1) for _ in range(len(root)+1)] def dfs(node): if not node: return for child in node.children: dfs(child) for k in range(j, 0, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-1] + node.value) for child in node.children: for k in range(j, 0, -1): for l in range(k-1, -1, -1): dp[node.value][k] = max(dp[node.value][k], dp[node.value][k-l-1] + dp[child.value][l]) dfs(root) return dp[root.value][j] # 构建树 root = Node(1) root.children.append(Node(2)) root.children.append(Node(3)) root.children[0].children.append(Node(4)) root.children[0].children.append(Node(5)) root.children[1].children.append(Node(6)) # 求解最大奖金 j = 3 max_bonus_value = max_bonus(root, j) print("最大奖金为:", max_bonus_value) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值