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的更多相关文章

  1. luogu P3567 [POI2014]KUR-Couriers

    二次联通门 : luogu P3567 [POI2014]KUR-Couriers MMP 指针 RE + MLE + WA..... 不得已...向黑恶的数组实力低头 /* 指针 */ #inclu ...

  2. 主席树||可持久化线段树||BZOJ 3524: [Poi2014]Couriers||BZOJ 2223: [Coci 2009]PATULJCI||Luogu P3567 [POI2014]KUR-Couriers

    题目:[POI2014]KUR-Couriers 题解: 要求出现次数大于(R-L+1)/2的数,这样的数最多只有一个.我们对序列做主席树,每个节点记录出现的次数和(sum).(这里忽略版本差值问题) ...

  3. [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 ...

  4. luogu P3565 [POI2014]HOT-Hotels

    传送门 无脑暴力+O2=AC 题目要统计距离两两相等的三个点的组数,这三个点之间显然有一个点,并且这三个点到这个点的距离都相同.所以枚举中间这个点作为根,然后bfs整棵树,对于每一层,把以根的某个儿子 ...

  5. luogu P3576 [POI2014]MRO-Ant colony

    传送门 一群蚂蚁能被吃,也就是走到指定边的两端点之一要走到另一端点时有\(k\)只,我们可以从这两端点逆推,记两个值为走到某个点时最后会被吃掉\(k\)只蚂蚁的蚂蚁数量范围,式子下面有,很好理解(雾) ...

  6. Luogu P3579 [POI2014]PAN-Solar Panels

    题目大意: 给出T组询问,每组询问给出四个数a,b,c,d,每次询问满足a<=x<=b,c<=y<=d的gcd(x,y)的最大值 首先可以想到如果存在gcd(x,y)=k,那么 ...

  7. 洛谷P3577 [POI2014]TUR-Tourism

    给定一个n个点,m条边的无向图,其中你在第i个点建立旅游站点的费用为Ci.在这张图中,任意两点间不存在节点数超过10的简单路径.请找到一种费用最小的建立旅游站点的方案,使得每个点要么建立了旅游站点,要 ...

  8. luogu P3572 [POI2014]PTA-Little Bird |单调队列

    从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力 #include<cstdio> #include<cstring> #i ...

  9. luogu P3572 [POI2014]PTA-Little Bird

    题目描述 从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力 单调队列优化动态规划 #include<cstdio> #include&l ...

随机推荐

  1. Oracle讨论Java 13版本

    JDK 13提高了应用程序性能,添加了两种语言功能预览,以及更多JDK 13  根据Oracle Java Team的说法,JDK 13致力于通过提高Java SE平台和JDK的性能,稳定性和安全性来 ...

  2. 2019年9月Github上最热门的JavaScript开源项目

      2019年9月Github上最热门的JavaScript开源项目 前端开发 前端开发 微信号 qianduan1024 功能介绍 专注于Web前端技术文章分享,包含JavaScript.HTML5 ...

  3. 编译安装最新版nettle和gnutls

    编译安装最新版gnutls的时候,总是会出libnettle 3.4.1 was not found的报错信息. 即使编译安装了nettle的最新版3.5之后,依然会报该错. 原因是gnutls编译的 ...

  4. 解决:perl: warning: Please check that your locale settings

    问题: perl: warning: Setting locale failed. perl: warning: Please check that your locale settings: LAN ...

  5. 前端之CSS1

    CSS基本语法和引入方式 CSS介绍 为了让网页元素的样式更加丰富,也为了让网页的内容和样式能拆分开,CSS由此而诞生,CSS是 Cascading Style Sheets 的首字母缩写,意思是层叠 ...

  6. django中're_path'的用法

    1.re_path和path的作用是一样的.只不过're_path'是在写url的时候可以用正则表达式,功能更加强大.2.写正则表达式都推荐使用原生字符串.也就是以‘r’开头的字符串:r'move/' ...

  7. Python笔记:设计模式之工厂模式

    工厂模式:“工厂”即表示一个负责创建其他类型的对象的类,通常情况下,一个工厂的对象会有一个或多个方法与之关联,这些方法用于创建不同类型的对象,工厂对象会根据客户端给方法传递的不同的参数或者客户端调用不 ...

  8. 垃圾分类环保宣传 PPT模板

    模板来源:http://ppt.dede58.com/peixunyanjiang/26263.html

  9. PLSQL 12 安装、连接Oracle

    点击下载PLSQL,本次安装的PLSQL版本为12.0.7,建议安装64位. 下载PLSQL时,版本旁边会有个“Language pack”的链接,点击后左侧选择“Chinese”即可下载汉化包. 注 ...

  10. 【LeetCode】70. 爬楼梯

    爬楼梯 假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意: 给定 n 是一个正整数. 示例 1: 输入: 2 输出: 2 解 ...