JZOJ 5442. 【NOIP2017提高A组冲刺11.1】荒诞

来源:互联网 发布:手机淘宝怎么没有直播 编辑:程序博客网 时间:2024/06/05 04:08

题目

有一个n个点,m条边的无向图,第i个点建立一个旅游站点的费用是c_i。特别地,这张图中的任意两点间不存在节点数超过10的简单路径。
我想要建造一些旅游站点使得每个点要么建立了旅游站点,要么与它有边直接相连的点里至少有一个点建立了旅游站点。我还希望这个建造方案总花费尽量少。
请求出这个花费。
数据范围
对于前30%的测试点,满足1<=n<=20,0<=m<=50。
对于另外15%的测试点,满足每个连通块都是一棵树。
对于100%的测试点,满足
1<=n<=2104,0<=m<=2.5104,0<=ci<=104

题解

30分肯定枚举选哪个不选哪个。
另15分直接树形DP。

AC做法

题目条件

选了一个点,与之相连的点可以不选。
以任何一点为根的dfs树深度不超过10。

困惑点

有返祖边干扰了转移。
只确定当前点的状态满足不了题目的需求。

准确做法

考虑树形DP。
考虑怎么样避免返祖边的干扰。一个新知识:欧拉序。
欧拉序,就是从根遍历到每个点,再回到根的经过的点的序列。
如果第二次到点x,说明x的子树已经处理完了,可以更新到x。
那么可以考虑基于欧拉序的DP。
f[x][s]表示做到x,x到根节点的点状态为s(s为三进制数,0表示没有覆盖到也没选,1表示被覆盖到,2表示被选)
那么枚举状态s,讨论x是否被选两种情况就可以DP。(设x的父亲是y)
①没有被选:由于返祖边的干扰,我们先确定与之有边连着的祖先是否被选,如果是的话x一定会被覆盖到f[x][s+3dep[x]1]f[y][s],否则不会f[x][s]f[y][s]
②被选:那么会影响到与之有边连着的祖先。
设这个新状态为s1,则有f[x][s1]f[y][s]+c[x]
接下来递归子树。由于第一次遍历到x点时为讨论到x的子树更新x的情况,所以f[x][s]要重新被算一次。由于x的祖先转移到x的情况已经传给了x的子树,所以递归回来的时候(设x的儿子为y)直接f[x][s]=min(f[y][s+3dep[y]1],f[y][s+23dep[y]1])

代码

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 20010#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;struct note{    int to,next;};note edge[N*5/2];int i,j,k,l,n,m;int dep[N],ans,fa[N];int c[N],u,v;int head[N],tot;int f[2][59050];int _3[13];bool bz[N],bb[13];int read(){    int fh=1,res=0;char ch;    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();    if(ch=='-')fh=-1,ch=getchar();    while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();    return res*fh;}void lb(int x,int y){    edge[++tot].to=y;    edge[tot].next=head[x];    head[x]=tot;}void mix(int &x,int y){x=x<y?x:y;}void dg(int x){    bz[x]=1;    int o=dep[x]&1;    bool pp;    memset(f[o],63,sizeof(f[o]));    memset(bb,0,sizeof(bb));    int i,s,s1;    for(i=head[x];i;i=edge[i].next)        if(dep[edge[i].to]<dep[x])bb[dep[edge[i].to]]=1;    fo(s,0,_3[dep[x]]-1)    if(f[1^o][s]<1061109567){        s1=s+_3[dep[x]]*2;        pp=0;        fo(i,1,dep[x]-1)            if(bb[i]){                if(((s1/_3[i])%3)==0)s1+=_3[i];                if(((s/_3[i])%3)==2)pp=1;            }        mix(f[o][s1],f[1^o][s]+c[x]);        if(pp)mix(f[o][s+_3[dep[x]]],f[1^o][s]);         else mix(f[o][s],f[1^o][s]);    }    for(i=head[x];i;i=edge[i].next)        if(!bz[edge[i].to]){            fa[edge[i].to]=x;            dep[edge[i].to]=dep[x]+1;            dg(edge[i].to);            fo(s,0,_3[dep[edge[i].to]]-1)                f[o][s]=min(f[1^o][s+_3[dep[edge[i].to]]],f[1^o][s+_3[dep[edge[i].to]]*2]);        }}int main(){    _3[1]=1;fo(i,2,12)_3[i]=_3[i-1]*3;    n=read(),m=read();    fo(i,1,n)c[i]=read();    fo(i,1,m){        u=read(),v=read();        lb(u,v),lb(v,u);    }    fo(i,1,n)        if(!bz[i]){            memset(f,63,sizeof(f));            f[0][0]=0;            dep[i]=1;            dg(i);            ans+=min(f[1][1],f[1][2]);         }    printf("%d",ans);    return 0;}
阅读全文
1 0
原创粉丝点击