topcoder srm 679 div1 -3

1、给定一棵有根树,每个节点有一个权值(有正有负)。裁剪掉一些子树使得最后所有节点的权值和最大?

思路:$f[u][0],f[u][1]$表示$u$节点表示的子树去掉和不去掉节点$u$的最大权值。

#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <assert.h>
using namespace std;

const int N=3005;

vector<int> g[N];
int n;
int a[N];

int f[N][2];


void dfs(int u)
{
    f[u][0]=0;
    f[u][1]=a[u];
    for(int i=0;i<(int)g[u].size();++i)
    {
        int v=g[u][i];
        dfs(v);
        f[u][1]+=max(f[v][0],f[v][1]);
    }
}

class FiringEmployees
{
public:
    int fire(vector<int> manager,vector<int> salary,vector<int> productivity)
    {
        n=(int)manager.size();
        for(int i=0;i<n;++i) {
            g[manager[i]].push_back(i+1);
        }
        for(int i=1;i<=n;++i) {
            a[i]=productivity[i-1]-salary[i-1];
        }
        dfs(0);
        return f[0][1];
    }
};

2、给定二维平面上$n$个蓝点和$m$个红点。任意三点不共线,任意两点不重合。选择一个凸包使其在不包含红点的前提下包含的蓝点尽可能多?输出最多的蓝点个数。$n,m \leq 50$

思路:首先预处理计算任意三个蓝点组成的三角形中的蓝点个数以及是否包含红点。凸包可以分割成三角形。首先初始化凸包的三个顶点为$x,y,z$(假设$x,y,z$是逆时针),然后每次增加一个新的点进来,设最后加入凸包的两个点为$p_{1},p_{2}$,新加入的点为$q$,那么$q$需要满足的条件为:

(1)三角形$x,p_{2},q$中没有红点;

(2)$q$在射线$x,p_{2}$的左侧;

(3)$q$在射线$p_{1},p_{2}$的左侧;

(4)$q$在射线$x,y$的左侧.

这样进行记忆化搜索即可。

#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <assert.h>
using namespace std;



struct point
{
    double x,y;

    point(){}
    point(double _x,double _y) {x=_x; y=_y;}

    point operator+(point a) { return point(x+a.x,y+a.y); }
    point operator-(point a) { return point(x-a.x,y-a.y); }
    double operator*(point a) { return x*a.y-y*a.x; }
    double operator^(point a) { return x*a.x+y*a.y; }
    point operator*(double t) { return point(x*t,y*t); }
    point operator/(double t) { return point(x/t,y/t); }
    point verlLeft() { return point(-y,x); }
    point verlRight() { return point(y,-x); }
    void read() { scanf("%lf %lf",&x,&y);}
};


#define EPS 1e-12

int sgn(double x)
{
    if(x>EPS) return 1;
    if(x<-EPS) return -1;
    return 0;
}

double cross(point a,point b,point p)
{
    return (b-a)*(p-a);
}


int onLeft(point a,point b,point p)
{
    return ((b-a)*(p-a))>0;
}

double getArea(point a,point b,point c)
{
    return fabs(cross(a,b,c))*0.5;
}



int inside(point a,point b,point c,point d)
{
    double s=getArea(a,b,c);
    double S=getArea(a,b,d)+getArea(a,c,d)+getArea(b,c,d);
    return sgn(s-S)==0;
}

const int N=55;

point p[N],q[N];
int n,m;

int dp[N][N][N];

int cal(point a,point b,point c)
{
    double s=getArea(a,b,c);
    for(int i=1;i<=m;++i)
    {
        double S=getArea(a,b,q[i])+getArea(a,c,q[i])+getArea(b,c,q[i]);
        if(sgn(S-s)==0) return 1;
    }
    return 0;
}

int f[N][N][N];


struct node
{
    int i,j,t,cnt;

    node(){}
    node(int _i,int _j,int _t,int _cnt):i(_i),j(_j),t(_t),cnt(_cnt) {}
};

queue<node> Q;
int inq[N][N][N];
int g[N][N][N];

int get(const int id)
{
    memset(f,0,sizeof(f));
    memset(inq,0,sizeof(inq));
    while(!Q.empty()) Q.pop();
    int ans=0;

    for(int i=1;i<=n;++i) {
        for(int j=1;j<=n;++j) {
            if(i!=id&&i!=j&&j!=id&&!dp[id][i][j]&&onLeft(p[id],p[i],p[j])) {
                f[i][i][j]=3+g[id][i][j];
                ans=max(ans,f[i][i][j]);
                inq[i][i][j]=1;
                Q.push(node(i,j,i,f[i][i][j]));
            }
        }
    }
    while(!Q.empty())
    {
        node pp=Q.front(); Q.pop();
        inq[pp.t][pp.i][pp.j]=0;

        for(int i=1;i<=n;++i)
        {
            if(i==id||i==pp.i||i==pp.j||i==pp.t||dp[id][pp.j][i]) continue;
            if(onLeft(p[pp.i],p[pp.j],p[i])
             &&onLeft(p[id],  p[pp.j],p[i])
             &&onLeft(p[id],  p[pp.t],p[i])) {
                 int sum=pp.cnt+1+g[pp.j][i][id];
                 if(f[pp.t][pp.j][i]<sum) {
                    f[pp.t][pp.j][i]=sum;
                    ans=max(ans,sum);
                    if(!inq[pp.t][pp.j][i]) {
                        inq[pp.t][pp.j][i]=1;
                        Q.push(node(pp.j,i,pp.t,sum));
                    }
                }
            }
        }
    }
    return ans;
}

class RedAndBluePoints
{
public:
    int find(vector<int> blueX,vector<int> blueY,vector<int> redX,vector<int> redY)
    {
        n=(int)blueX.size();
        if(n<=2) return n;

        for(int i=1;i<=n;++i) {
            p[i]=point(blueX[i-1],blueY[i-1]);
        }
        m=(int)redX.size();
        for(int i=1;i<=m;++i) {
            q[i]=point(redX[i-1],redY[i-1]);
        }

        for(int i=1;i<=n;++i) {
            for(int j=1;j<=n;++j) {
                for(int k=1;k<=n;++k) {
                    if(i!=j&&i!=k&&j!=k) {
                        dp[i][j][k]=cal(p[i],p[j],p[k]);
                        for(int t=1;t<=n;++t) {
                            if(t!=i&&t!=j&&t!=k&&inside(p[i],p[j],p[k],p[t])) {
                                ++g[i][j][k];
                            }
                        }
                    }
                }
            }
        }

        int ans=2;
        for(int i=1;i<=n;++i)
        {
            ans=max(ans,get(i));
        }
        return ans;
    }
};

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值