• [LOJ#10157]皇宫看守


    题面

    这里(〃'▽'〃)

    题意

      大概就是有一棵n个节点的树,i号节点有一个费用wi。可以在某些点上安置侍卫监察,与该点相邻的点都视为安全。求使整棵树安全所需最小费用。

    闲扯

      一眼秒出做法树形dp,接着想到用dp[0][i]表示i点无侍卫,dp[1][i]表示i点有侍卫来进行转移,然鹅此题监察的是点而不是边...GG
      于是需要额外考虑i点的状态。

    分析

    我们重新定义dp方程:
      - dp[0][u]表示u点有人且安全时整棵子树的最小费用;
      - dp[1][u]表示u点无人但安全时整棵子树的最小费用;
      - dp[2][u]表示u点无人且不安全时整棵子树的最小费用。
    注意我们钦定上述条件建立在u的孩子都安全的基础上.
    易得dp[0][u],dp[2][u]的转移:
      (·dp[0][u]=sum minlbrace dp[0][v],dp[1][v],dp[2][v] brace +w[u])
      (·dp[2][u]=sum dp[1][v])
      (v为u的儿子)
      解释:当u点有人时v点可以被监察,故可以是任何状态;当u点无人且不安全时v点不能有人,但必须安全。


    于是本题最大的难点就在于dp[1][u]的转移:
      u点无人,但是安全说明u的儿子都安全且其中至少有一个是有人的。若不考虑u点的安全问题,方程是这样的:(dp[1][u]=sum minlbrace dp[0][v],dp[1][v] brace)
      我们发现,当dp[0][v]<dp[1][v]时,v会将"有人"的状态转移给u,这样u就安全了;于是我们考虑当所有的dp[0][v]都大于dp[1][v]的时候,一定要找一个损失尽量少,即使dp[0][v]-dp[1][v]最小的那个v.

    代码

    具体见代码注释.

    #include <iostream>
    #include <cstdio>
    #include <cctype>
    #define il inline
    #define vd void
    #define rg register
    #define rep(i,x,y) for(rg int i=x;i<=y;++i)
    #define drp(i,x,y) for(rg int i=x;i>=y;--i)
    using namespace std;
    const int Len=2333333,mn=1505;
    char buf[Len],*p1=buf,*p2=buf,duf[Len],*q1=duf;
    il char gc(); il int rd(); il vd pc(char c); il vd rt(int x); il vd flush();
    template<class T> il T Max(T a,T b){return a>b?a:b;}
    template<class T> il T Min(T a,T b){return a<b?a:b;}
    int n,u,v,cnt,m,w[mn],h[mn],fa[mn],dp[3][mn];
    struct E{int to,nxt;}e[mn<<1];
    il vd Add(int u,int v){e[++cnt]=(E){v,h[u]},h[u]=cnt;}
    vd Dfs(int u){int fake=5e8,f=0;  //保险些的话极大值可以再小点;f为标记
    	dp[0][u]=w[u]; //u点有人需花费
    	for(rg int i=h[u];i;i=e[i].nxt){int v=e[i].to; //v为子节点
    		if(v!=fa[u]){
    			fa[v]=u,Dfs(v),dp[0][u]+=Min(dp[0][v],Min(dp[1][v],dp[2][v])), //转移dp[0][u]
    			dp[2][u]+=dp[1][v],dp[1][u]+=Min(dp[0][v],dp[1][v]);  //转移dp[2][u]和dp[1][u]
    			if(dp[0][v]<dp[1][v]) f=1;  //u点能做到安全,标记为1
    			if(!f) fake=Min(fake,dp[0][v]-dp[1][v]); //否则尽量使损失变少
    		}
    	}
    	if(!f) dp[1][u]+=fake; //u点还是不能做到安全,要手动在v上放人,用最少的损失
    }
    int main(){
    	n=rd();
    	rep(i,1,n){
    		u=rd(),w[u]=rd(),m=rd();
    		while(m--) v=rd(),Add(u,v),Add(v,u); //加边,注意输入数据不保证1没有父亲
    	}
    	Dfs(1),rt(Min(dp[0][1],dp[1][1])); //以1为根,最后根节点必须安全
    	return flush(),0;
    } //以下为读优输优主体~~喵喵喵~~
    
    il char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Len,stdin),p1==p2)?-1:*p1++;}
    il int rd(){char c; int f=1;
    	while(!isdigit(c=gc())&&c!='-');
    	c=='-'?f=-1,c=gc():0; int x=c^48;
    	while(isdigit(c=gc())) x=((x+(x<<2))<<1)+(c^48);
    	return x*f;
    }
    il vd pc(char c){q1==duf+Len&&fwrite(q1=duf,1,Len,stdout),*q1++=c;}
    il vd rt(int x){x<0?pc('-'),x=-x:0,pc((x>=10?rt(x/10),x%10:x)+48);}
    il vd flush(){fwrite(duf,1,q1-duf,stdout);}
    

    第一篇blog完结撒花!ヾ(@@)ノ

  • 相关阅读:
    python unittest一个简单的实例
    解决python编码格式错误问题
    一个简便的方法,获取某个页面元素的Xpath值
    Xpath基础语法学习
    postman发送带cookie的http请求
    postman测试接口之POST提交本地文件数据
    使用Jmeter录制web脚本
    mac 之 jmeter下载、解压、启动
    第三方测评公司的一些基础理念
    jmeter简单的压测案例——访问百度并发5,持续请求15
  • 原文地址:https://www.cnblogs.com/Shallowy/p/9712013.html
Copyright © 2020-2023  润新知