[BZOJ4472]-[Jsoi2015]salesman-贪心

说在前面

这个水题写了我一个白天= =
就因为建边忘了建双向边,以为所有给的边都是father->son的
简直*了狗(狗:woc关我啥事)


题目

BZOJ4472传送门

题目大意

给你一棵含有n个节点的树,每个节点有权值(可正可负),并且每个节点有路过次数上限。仅在第一次路过某个节点后,获得该节点的权值。现问从1号节点出发,在树上随便跑(可以不进入某些节点)后能获得的最大收益,并输出方案是否唯一。
若唯一,输出solution is unique
else,输出solution is not unique
方案唯一是指:至少有两个方案可以达到该权值,并且此两方案路过的节点不至少有一个点不同。

输入

第一行一个整数:n,代表总节点数。
第二行n-1个整数,代表第二到第n个点的权值
第三行n-1个整数,代表第二到第n各节点最大可路过次数
接下来n-1行,每行两个整数,代表此两节点之间有一条边。
9
-3 -4 2 4 -2 3 4 6
4 4 2 2 2 2 2 2
1 2
1 3
1 4
2 5
2 6
3 7
4 8
4 9
数据保证每个节点路过次数不小于二,并且从1可以到达任意一点,即整个图是联通的,不是森林。1号节点进入次数不限,权值为0.

输出

9
solution is unique


解法

一开始看到这个题可能会想到树形背包
然而这道题因为不确定选点的个数,因此背包的容积是不确定的,因此不能用背包做。
看到这里,请读者仔细思考一下该题正解:
·
·
·
·
·
·
·
·
·
·
·
如果还没想出来–>请回头看一下本文标题
.
.
.
.
.
.
.
.
.
.
.
可以发现,节点的权值有正有负,由于我们路过点的次数有限,那么我们肯定是尽量的把正权值的点选完

于是思路出来了:
递归处理每个子节点,然后把已经处理好的子节点的最优解从大到小排序,如果正权值已经选完,或者选的节点到达上限,就退出循环。

那么如何确定解是不是唯一呢?
在把子树的最大收益计算出来之后,是排了一遍 续....续1s!序的。如果当前选择的最后一个节点,和第一个me没选的节点收益一样,那么方案不唯一。如果me选中的节点中有收益为0的,那么方案也不唯一。


下面是自带大常数的代码:

其中,pro[i]代表的是点i的初始利润
dp数组为处理之后,路过改点获得的最大收益
isnotuni==is not unique
tim[i]表示i点最大可经过次数
其余的应该都能懂 ~

/* *************************************************************
    Problem: 4472
    User: Izumihanako
    Language: C++
    Result: Accepted
    Time:336 ms
    Memory:4340 kb
*************************************************************** */

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int n,pro[100001],tim[100001],head[100001],tw=0;
int dp[100001],isnotuni[100001];
struct node{
    int pre,to;
}w[200001];

int comp(const pair<int,int > &a,const pair<int,int > &b){
    if(a.first<b.first)  return 0;
    return 1;
}

void In(int t1,int t2){
    w[++tw].pre=head[t1];
    w[tw].to=t2;
    head[t1]=tw;
}

void work(int u,int f){
    vector< pair<int,int> > Ve;
    Ve.clear();
    for(int i=head[u];i;i=w[i].pre){
        int v=w[i].to;
        if(v==f)    continue;
        work(v,u);
        Ve.push_back(make_pair<int,int>(dp[v],v));
    }
    sort( Ve.begin(), Ve.end(), comp);
    int i=0,R=Ve.size()-1;
    for(;i<=R&&i+2<=tim[u]&&Ve[i].first>=0;i++){
        isnotuni[u]|=isnotuni[Ve[i].second];
        dp[u]+=Ve[i].first;
    }
    if(i>0&&i!=Ve.size())
        isnotuni[u]|=(Ve[i-1].first==Ve[i].first ? 1 : 0);
    if(i>0&&Ve[i-1].first==0)
        isnotuni[u]=1;
    dp[u]+=pro[u];
}

inline int read()
{
    int data=0,w=1; char ch=0;
    while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
    return data*w;
}

int main(){
    int t1,t2;
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
        pro[i]=read();
    for(int i=2;i<=n;i++)
        tim[i]=read();
    tim[1]=0x3f3f3f3f;
    for(int i=2;i<=n;i++){
        t1=read();t2=read();
        In(t1,t2);
        In(t2,t1);
    }
    work(1,0);
    printf("%d\n",dp[1]);
    if(isnotuni[1]==1)
        printf("solution is not unique");
    else
        printf("solution is unique");
    return 0;
}
内容概要:本文详细介绍了扫描单分子定位显微镜(scanSMLM)技术及其在三维超分辨体积成像中的应用。scanSMLM通过电调透镜(ETL)实现快速轴向扫描,结合4f检测系统将不同焦平面的荧光信号聚焦到固定成像面,从而实现快速、大视场的三维超分辨成像。文章不仅涵盖了系统硬件的设计与实现,还提供了详细的软件代码实现,包括ETL控制、3D样本模拟、体积扫描、单分子定位、3D重建和分子聚类分析等功能。此外,文章还比较了循环扫描与常规扫描模式,展示了前者在光漂白效应上的优势,并通过荧光珠校准、肌动蛋白丝、线粒体网络和流感A病毒血凝素(HA)蛋白聚类的三维成像实验,验证了系统的性能和应用潜力。最后,文章深入探讨了HA蛋白聚类与病毒感染的关系,模拟了24小时内HA聚类的动态变化,提供了从分子到细胞尺度的多尺度分析能力。 适合人群:具备生物学、物理学或工程学背景,对超分辨显微成像技术感兴趣的科研人员,尤其是从事细胞生物学、病毒学或光学成像研究的科学家和技术人员。 使用场景及目标:①理解和掌握scanSMLM技术的工作原理及其在三维超分辨成像中的应用;②学习如何通过Python代码实现完整的scanSMLM系统,包括硬件控制、图像采集、3D重建和数据分析;③应用于单分子水平研究细胞内结构和动态过程,如病毒入侵机制、蛋白质聚类等。 其他说明:本文提供的代码不仅实现了scanSMLM系统的完整工作流程,还涵盖了多种超分辨成像技术的模拟和比较,如STED、GSDIM等。此外,文章还强调了系统在硬件改动小、成像速度快等方面的优势,为研究人员提供了从理论到实践的全面指导。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值