[置顶] 【JZOJ5442】【NOIP2017提高A组冲刺11.1】荒诞[状压dp]
2017-11-01 16:50
393 查看
Description
我的灵魂与我之间的距离如此遥远,而我的存在却如此真实。——加缪《局外人》
我醒来的时候,发现满天星斗照在我的脸上。田野上的声音一直传到我的耳畔。夜的气味,土地的气味,海盐的气味,使我的两鬓感到清凉。这沉睡的夏夜的奇妙安静,像潮水一般浸透我的全身。这时,长夜将尽,汽笛叫了起来。它宣告有些人踏上旅途,要去一个从此和我无关痛痒的世界。
这时我在想一个问题:我有一个n个点,m条边的无向图,第i个点建立一个旅游站点的费用是c_i。特别地,这张图中的任意两点间不存在节点数超过10的简单路径。
为了把一切都做得完善,为了使我感到不那么孤独,我想要建造一些旅游站点使得每个点要么建立了旅游站点,要么与它有边直接相连的点里至少有一个点建立了旅游站点。我还希望这个建造方案总花费尽量少。
请求出这个花费。
Data Constraint
对于前10%的测试点,满足所有的c_i相等。对于前30%的测试点,满足1<=n<=20,0<=m<=50。
对于另外15%的测试点,满足每个连通块都是一棵树。
对于100%的测试点,满足1<=n<=2*10^4,0<=m<=2.5*10^4,0<=c_i<=10^4。
Solution
另外15%的测试点相信很基础,我们设一个f[x][0..2]表示当前以x为根的子树内的最小代价。0表示x不选并且没被覆盖,1表示x不选但被覆盖,2表示选了x。前30分告诉我们可以用状压。100分我们沿用这两个算法。由于任意两点间不存在节点数超过10的简单路径,这说明我们若做一棵dfs树,树的深度不会超过10,我们考虑状压。设f[x][S]表示当前做到第x个节点,根到x的节点的3进制状态为S的最小代价。第i位0表示第i个点不选并且没被覆盖,1表示不选但被覆盖,2表示选了。我们每次由父亲转移至儿子时,我们可以枚举状态S,将x选择的贡献、x被覆盖、x没被选择覆盖的加入考虑形成S’,当我们做完儿子y返回至父亲x时,由于S内只能存储根到x的节点,但我们又不能忽略y节点,以后的转移中y必须被覆盖或选择。所以我们将x的f[x][S]修改为f[y][S+3^y]和f[y][S+2*3^y]的最小值,即y要么被覆盖要么被选择。Code
#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int maxn=5e4+5,maxn1=59049; int first[maxn],last[maxn],next[maxn],f[2][maxn1],a[maxn],bz[maxn],er[maxn],d[maxn]; int n,m,i,t,j,k,l,x,y,z,num,p,ln,ans,mx; void lian(int x,int y){ last[++num]=y;next[num]=first[x];first[x]=num; } void dg(int x,int y,int p){ int t; d[x]=++num;bz[x]=1; memset(f[p],127,sizeof(f[p])); for (i=0;i<er[num];i++){ if (f[1-p][i]==mx) continue; f[p][i]=f[1-p][i];l=i+2*er[num]; for (t=first[x];t;t=next[t]){ if (!bz[last[t]]) continue; k=i/er[d[last[t]]]; if (k%3==0) l+=er[d[last[t]]]; if (k%3==2) f[p][i+er[num]]=min(f[p][i+er[num]],f[1-p][i]); } f[p][l]=min(f[p][l],f[1-p][i]+a[x]); } for (t=first[x];t;t=next[t]){ if (bz[last[t]]) continue; dg(last[t],x,1-p); for (i=0;i<er[num];i++)f[p][i]=min(f[1-p][i+er[num]*2],f[1-p][i+er[num]]); num--; } } int main(){ freopen("absurdity.in","r",stdin);freopen("absurdity.out","w",stdout); scanf("%d%d",&n,&m);er[1]=1; for (i=2;i<=10;i++)er[i]=er[i-1]*3; for (i=1;i<=n;i++)scanf("%d",&a[i]); for (i=1;i<=m;i++)scanf("%d%d",&x,&y),lian(x,y),lian(y,x); ln=er[10]-1;num=0; for (i=1;i<=n;i++){ if (bz[i]) continue; memset(f[0],127,sizeof(f[0]));f[0][0]=0;mx=f[0][1];num=0; dg(i,0,1); ans+=min(f[1][2],f[1][1]); } printf("%d\n",ans); }
相关文章推荐
- 【JZOJ 5442】【NOIP2017提高A组冲刺11.1】荒诞
- JZOJ5442. 【NOIP2017提高A组冲刺11.1】荒诞
- [JZOJ5442]【NOIP2017提高A组冲刺11.1】荒诞([BZOJ3060]【POI2012】Tour de Byteotia)
- JZOJ 5442. 【NOIP2017提高A组冲刺11.1】荒诞
- Jzoj5440 【NOIP2017提高A组冲刺11.1】背包
- JZOJ5441. 【NOIP2017提高A组冲刺11.1】序列 启发式搜索+迭代深搜
- 【JZOJ 5441】【NOIP2017提高A组冲刺11.1】序列
- JZOJ5440. 【NOIP2017提高A组冲刺11.1】背包
- JZOJ 5440. 【NOIP2017提高A组冲刺11.1】背包
- JZOJ 5441. 【NOIP2017提高A组冲刺11.1】序列
- JZOJ5442【NOIP2017提高A组冲刺11.1】荒诞 三进制状压+欧拉序
- JZOJ 5440. 【NOIP2017提高A组冲刺11.1】背包
- JZOJ 5441. 【NOIP2017提高A组冲刺11.1】序列
- JZOJ 5460. 【NOIP2017提高A组冲刺11.7】士兵训练
- JZOJ 5443. 【NOIP2017提高A组冲刺11.2】字典序
- JZOJ 5459. 【NOIP2017提高A组冲刺11.7】密室
- JZOJ5463. 【NOIP2017提高A组冲刺11.8】证书
- JZOJ 5444. 【NOIP2017提高A组冲刺11.2】救赎
- JZOJ 5462. 【NOIP2017提高A组冲刺11.8】好文章
- JZOJ5465. 【NOIP2017提高A组冲刺11.9】道路重建