Luogu P3577 [POI2014]TUR-Tourism
Luogu P3577 [POI2014]TUR-Tourism
题目大意:给出一张\(n\)个点,\(m\)条边的无向图,保证任意两点之间没有点数超过\(10\)的简单路径。选择第\(i\)个点要支付\(C_i\)的代价,要求用最小的代价使得每个点被选择或者与一个被选择的点相邻。
\(n\leq 20000,m\leq 25000,C_i\leq 1000\)。
可以发现,如果原问题是在树上的话就很简单。所以我们先建出\(dfs\)树。因为这是无向图,所以所有的非树边都是返祖边。由题目中那个神奇的性质,我们可以知道,这棵树的深度不超过\(10\)。
于是我们可以状压。设\(f_{i,S}\)表示第\(i\)个点,其祖先的状态为\(S\)的最小代价。
状压的状态有三种:
0:没有选择且没被覆盖
1.没有选择但被覆盖了
2.选择了
转移就有点厉害,据说是泛化背包。
当由\(fa_v\)递归到\(v\)的时候,\(dfs\)序比\(v\)小的点中除了\(v\)到根这条链上都已经被覆盖了。然后将\(f_{fa_v,S}\)的\(DP\)值继承给\(f_{v,S'}\)。继承的时候讨论是否选择\(v\)得到\(S'\)。
一直递归到底后回溯,\(f_{fa_v,S}=\min\{f_{v,S+3^{dep_v}},f_{v,S+2*3^{dep_v}}\}\)。接着递归下一个儿子。这个\(DP\)是按\(dfs\)序来的,当一个点出栈了过后,保证这个点已经被覆盖,无需再考虑。
\(DP\)的结果就是\(\min\{f_{root,1},f_{root,2}\}\)。将每个联通块的答案加起来就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 20005
#define M 25005
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n,m,C[N];
struct road {int to,nxt;}s[M<<1];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}
int pw[15];
bool vis[N];
int fa[N],dep[N];
int f[12][60000];
void dfs(int v) {
vis[v]=1;
if(dep[v]==0) {
f[0][0]=0;
f[0][1]=1e9;
f[0][2]=C[v];
} else {
for(int i=h[v];i;i=s[i].nxt) {
int to=s[i].to;
if(vis[to]) fa[v]|=1<<dep[to];
}
for(int S=0;S<pw[dep[v]+1];S++) f[dep[v]][S]=1e9;
for(int S=0;S<pw[dep[v]];S++) {
if(f[dep[v]-1][S]>=1e9) continue ;
bool flag=0;
for(int i=0;i<dep[v];i++) if((fa[v]>>i&1)&&S/pw[i]%3==2) flag=1;
f[dep[v]][S+flag*pw[dep[v]]]=min(f[dep[v]][S+flag*pw[dep[v]]],f[dep[v]-1][S]);
int T=S+2*pw[dep[v]];
for(int i=0;i<dep[v];i++) if((fa[v]>>i&1)&&S/pw[i]%3==0) T+=pw[i];
f[dep[v]][T]=min(f[dep[v]][T],f[dep[v]-1][S]+C[v]);
}
}
int flag=0;
for(int i=h[v];i;i=s[i].nxt) {
int to=s[i].to;
if(vis[to]) continue ;
dep[to]=dep[v]+1;
dfs(to);
for(int S=0;S<pw[dep[v]+1];S++) {
f[dep[v]][S]=min(f[dep[to]][S+pw[dep[to]]],f[dep[to]][S+2*pw[dep[to]]]);
}
}
}
int main() {
pw[0]=1;
for(int i=1;i<=10;i++) pw[i]=pw[i-1]*3;
n=Get(),m=Get();
for(int i=1;i<=n;i++) C[i]=Get();
for(int i=1;i<=m;i++) {
int a=Get(),b=Get();
add(a,b),add(b,a);
}
int ans=0;
for(int i=1;i<=n;i++) {
if(vis[i]) continue ;
dfs(i);
ans+=min(f[0][1],f[0][2]);
}
cout<<ans;
return 0;
}
Luogu P3577 [POI2014]TUR-Tourism的更多相关文章
- luogu P3567 [POI2014]KUR-Couriers
二次联通门 : luogu P3567 [POI2014]KUR-Couriers MMP 指针 RE + MLE + WA..... 不得已...向黑恶的数组实力低头 /* 指针 */ #inclu ...
- 主席树||可持久化线段树||BZOJ 3524: [Poi2014]Couriers||BZOJ 2223: [Coci 2009]PATULJCI||Luogu P3567 [POI2014]KUR-Couriers
题目:[POI2014]KUR-Couriers 题解: 要求出现次数大于(R-L+1)/2的数,这样的数最多只有一个.我们对序列做主席树,每个节点记录出现的次数和(sum).(这里忽略版本差值问题) ...
- [luogu]P3572 [POI2014]PTA-Little Bird(单调队列)
P3572 [POI2014]PTA-Little Bird 题目描述 In the Byteotian Line Forest there are nn trees in a row. On top ...
- luogu P3565 [POI2014]HOT-Hotels
传送门 无脑暴力+O2=AC 题目要统计距离两两相等的三个点的组数,这三个点之间显然有一个点,并且这三个点到这个点的距离都相同.所以枚举中间这个点作为根,然后bfs整棵树,对于每一层,把以根的某个儿子 ...
- luogu P3576 [POI2014]MRO-Ant colony
传送门 一群蚂蚁能被吃,也就是走到指定边的两端点之一要走到另一端点时有\(k\)只,我们可以从这两端点逆推,记两个值为走到某个点时最后会被吃掉\(k\)只蚂蚁的蚂蚁数量范围,式子下面有,很好理解(雾) ...
- Luogu P3579 [POI2014]PAN-Solar Panels
题目大意: 给出T组询问,每组询问给出四个数a,b,c,d,每次询问满足a<=x<=b,c<=y<=d的gcd(x,y)的最大值 首先可以想到如果存在gcd(x,y)=k,那么 ...
- 洛谷P3577 [POI2014]TUR-Tourism
给定一个n个点,m条边的无向图,其中你在第i个点建立旅游站点的费用为Ci.在这张图中,任意两点间不存在节点数超过10的简单路径.请找到一种费用最小的建立旅游站点的方案,使得每个点要么建立了旅游站点,要 ...
- luogu P3572 [POI2014]PTA-Little Bird |单调队列
从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力 #include<cstdio> #include<cstring> #i ...
- luogu P3572 [POI2014]PTA-Little Bird
题目描述 从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力 单调队列优化动态规划 #include<cstdio> #include&l ...
随机推荐
- Android Monkey的用法(一)
Monkey 简介 ü Monkey 是一个命令行工具,可以运行在 Android 模拟器里或真实设备中.它可以向系统发送伪随机(pseudo-random)的用户事件流(如按键输入.触摸屏输入 ...
- IT兄弟连 Java语法教程 数组 使用foreach循环遍历数组元素
从JDK5之后,Java提供了一种更简单的循环:foreach循环,也叫作增强for循环,这种循环遍历数组和集合更加简洁.使用foreach循环遍历数组和集合元素时,无需获得数组或集合的长度,无需根据 ...
- MySQL字符类型学习笔记
目录 一.字符集和字符编码 1.1.字符集 1.2.字符编码 二.字符集排序规则 2.1.排序规则定义 2.2 .排序规则特征 三.CHAR和VARCHAR 3.1.CHAR类型 3.2.VARCHA ...
- 支付签名 MD5Util 排序工具类
package com.skynet.wechat.wxPay.common; import java.security.MessageDigest; import java.util.Iterato ...
- OpenGL入门1.7:摄像机
每一个小步骤的源码都放在了Github 的内容为插入注释,可以先跳过 前言 我们已经知道了何为观察矩阵以及如何使用观察矩阵移动场景(我们向后移动了一点) OpenGL本身没有摄像机(Camera)的概 ...
- asp.net单一登录
asp.net 使用 Application 限制单一登录 原理:用户登录后系统会分配一个与用户唯一对应的SessionID,将当前用户ID与其SessionID对应保存在Application中,一 ...
- Oracle 中Number的长度定义
Number可以通过如下格式来指定:Field_NAME Number(precision ,scale),其中precision指Number可以存储的最大数字长度(不包括左右两边的0),scale ...
- Xamarin学习(一)---- 环境准备
前言: 摸索学习Xamarin的应用,以此博客跟进学习进度. 介绍: Xamarin 提供了用于移动设备.平板电脑和桌面应用程序的跨平台开发解决方案.Xamarin 产品依赖于 Apple 和 ...
- Apache—给一个站点绑定多个域名
前提简介: ServerAdmin:Apache服务管理员通知邮箱地址,如果有真实的邮箱地址也可以设置此值. ServerName:是服务的名字,只能填写一个域名. ServerAlias:serv ...
- 浅谈JS的toString
任何一个对象都有toString()方法(默认继承自Object,自己可以重写),此方法返回一个字符串. var sayYo = function () { alert("sayYo2!&q ...