题意

https://www.lydsy.com/JudgeOnline/problem.php?id=2595

思路

是一道比较裸的斯坦纳树呢~

题意等价于选出包含一些点的最小生成树,这就是斯坦纳树的功能。

举个例子,给定 \(n\) 个点,其中 \(k\) 个点被称作关键点,\(m\) 条带权边,求原图的一个权值最小的子图,这张子图图为包含这 \(k\) 个点的树。

我们定义 \(dp[i][j]\) 为关键点集合 \(i\) 与任意节点 \(j\) 连通的最小权的树。考虑转移这个 \(dp\) 数组,比较显然的是以下的子集划分:

\[dp[i][j]=\min(dp[k][j]+dp[i\setminus k][j])
\]

其中 \(k\) 是 \(i\) 的子集。

当然这样转移是不够的,在关键点集合 \(i\) 不变的情况下,\(j\) 有可能会发生改变,即发生如下转移:

\[\text{chk_min}(dp[i][k],dp[i][j]+w(j,k))
\]

其中 \(w(j,k)\) 为一条 \(j\) 指向 \(k\) 的边的边权。不难发现,这个过程和最短路的松弛操作是一样的,那么就可以利用最短路进行转移,没有负边就跑 \(\text{dijkstra}\),否则跑 \(\text{spfa}\) 。

这道题求的东西略微不同,是点有点权,不过无所谓,转移稍稍改动即可。然后还要输出方案,那么在 \(dp\) 转移的时候还需要记录从哪里转移过来。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
typedef long long ll;
template<const int N,const int M,typename T>struct LinkedList
{
int head[N],nxt[M],tot;T to[M];
LinkedList(){clear();}
T &operator [](const int x){return to[x];}
void clear(){memset(head,-1,sizeof(head)),tot=0;}
void add(int u,T v){to[tot]=v,nxt[tot]=head[u],head[u]=tot++;}
#define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
struct node
{
int at,path;
bool operator <(const node &_)const{return path>_.path;}
}; LinkedList<103,103*4,int>G;
std::priority_queue<node>Q;
int dp[(1<<10)+3][103];
bool lasknd[(1<<10)+3][103];
int las[(1<<10)+3][103];
bool mark[103];
int mp[103],ori[13];
int pw[103];
int n,m,K; inline int hs(int x,int y){return x*m+y;} void Steiner()
{
FOR(i,0,(1<<K)-1)FOR(j,0,n-1)dp[i][j]=1e9;
FOR(i,0,K-1)dp[1<<i][ori[i]]=0;
FOR(i,1,(1<<K)-1)
{
FOR(j,0,n-1)
for(int k=(i-1)&i;k;k=(k-1)&i)
if(chk_min(dp[i][j],dp[k][j]+dp[i^k][j]-pw[j]))
{
lasknd[i][j]=0;
las[i][j]=k;
}
while(!Q.empty())Q.pop();
FOR(j,0,n-1)Q.push((node){j,dp[i][j]});
while(!Q.empty())
{
node now=Q.top();Q.pop();
int u=now.at;
if(now.path>dp[i][u])continue;
EOR(k,G,u)
{
int v=G[k],w=pw[v];
if(chk_min(dp[i][v],dp[i][u]+w))
{
lasknd[i][v]=1;
las[i][v]=u;
Q.push((node){v,dp[i][v]});
}
}
}
}
} void backtrack(int i,int j)
{
mark[j]=1;
if(mp[j]!=-1&&i==(1<<mp[j]))return;
if(!lasknd[i][j])
backtrack(las[i][j],j),backtrack(i^las[i][j],j);
else backtrack(i,las[i][j]);
} int main()
{
scanf("%d%d",&n,&m);
FOR(i,0,n-1)FOR(j,0,m-1)
{
scanf("%d",&pw[hs(i,j)]);
if(!pw[hs(i,j)])mp[hs(i,j)]=K,ori[K]=hs(i,j),K++;
else mp[hs(i,j)]=-1;
}
FOR(i,0,n-1)FOR(j,0,m-2)
{
G.add(hs(i,j),hs(i,j+1));
G.add(hs(i,j+1),hs(i,j));
}
FOR(i,0,n-2)FOR(j,0,m-1)
{
G.add(hs(i,j),hs(i+1,j));
G.add(hs(i+1,j),hs(i,j));
}
n*=m;
Steiner();
int ans=1e9,id;
FOR(i,0,n-1)if(chk_min(ans,dp[(1<<K)-1][i]))id=i;
backtrack((1<<K)-1,id);
printf("%d\n",ans);
FOR(i,0,n-1)
{
if(!pw[i])putchar('x');
else putchar(mark[i]?'o':'_');
if(i%m==m-1)putchar('\n');
}
return 0;
}

WC 2008 观光计划(斯坦纳树)的更多相关文章

  1. 【BZOJ2595】[Wc2008]游览计划 斯坦纳树

    [BZOJ2595][Wc2008]游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为 ...

  2. Luogu 4294 [WC2008]游览计划 | 斯坦纳树

    题目链接 Luogu 4294 (我做这道题的时候BZOJ全站的SPJ都炸了 提交秒WA 幸好有洛谷) 题解 这道题是[斯坦纳树]的经典例题.斯坦纳树是这样一类问题:带边权无向图上有几个(一般约10个 ...

  3. bzoj2595: [Wc2008]游览计划 斯坦纳树

    斯坦纳树是在一个图中选取某些特定点使其联通(可以选取额外的点),要求花费最小,最小生成树是斯坦纳树的一种特殊情况 我们用dp[i][j]来表示以i为根,和j状态是否和i联通,那么有 转移方程: dp[ ...

  4. BZOJ2595: [Wc2008]游览计划(斯坦纳树,状压DP)

    Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 2030  Solved: 986[Submit][Status][ ...

  5. BZOJ 2595 [Wc2008]游览计划 ——斯坦纳树

    [题目分析] 斯坦纳树=子集DP+SPFA? 用来学习斯坦纳树的模板. 大概就是用二进制来表示树包含的点,然后用跟几点表示树的形态. 更新分为两种,一种是合并两个子集,一种是换根,换根用SPFA迭代即 ...

  6. bzoj2595 [Wc2008]游览计划——斯坦纳树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2595 今天刚学了斯坦纳树,还不太会,写一道题练习一下: 参考了博客:http://www.c ...

  7. P4294 [WC2008]游览计划 (斯坦纳树)

    题目链接 差不多是斯坦纳树裸题,不过边权化成了点权,这样在合并两棵子树时需要去掉根结点的权值,防止重复. 题目还要求输出解,只要在转移时记录下路径,然后dfs一遍就好了. #include<bi ...

  8. 【BZOJ-2595】游览计划 斯坦纳树

    2595: [Wc2008]游览计划 Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 1518  Solved: 7 ...

  9. 洛谷4294 [WC2008]游览计划——斯坦纳树

    题目:https://www.luogu.org/problemnew/show/P4294 大概是状压.两种转移,一个是以同一个点为中心,S由自己的子集拼起来:一个是S相同.中心不同的同层转移. 注 ...

随机推荐

  1. maven项目配置使用jdk1.8进行编译的插件

    在使用Maven插件编译Maven项目的时候报了这样一个错:[Java source1.5不支持diamond运算符,请使用source 7或更高版本以启用diamond运算符],这里记录下出现这个错 ...

  2. 『CSP2019初赛后的总结』

    初赛已经过去了,分数大概也已经知道了,接下来的一个月停课应该就是全部准备复赛. 联赛前几次讲课的内容是组合计数,计数\(dp\),字符串,概率期望,数论,数据结构,多数知识点难度都是大于联赛难度的,不 ...

  3. Java学习——枚举类

    Java学习——枚举类 摘要:本文主要介绍了Java的枚举类. 部分内容来自以下博客: https://www.cnblogs.com/sister/p/4700702.html https://bl ...

  4. java socket通信:聊天器(1)

    目的:实现多个客户之间的通信 首先,这个聊天器的框架是这样的: 对于服务器端:建立socket,连接到服务器,并且开始监听. import java.io.*; import java.util.Ar ...

  5. 操作系统原理之I/O设备管理(第六章上半部分)

    一.I/O系统的组成 I/O系统不仅包括各种I/O设备,还包括与设备相连的设备控制器,有些系统还配备了专⻔⽤ 于输⼊/输出控制的专⽤计算机,即通道.此外,I/O系统要通过总线与CPU.内存相连. I/ ...

  6. SQLi-LABS Page-2 (Adv Injections) Less27-Less29

    Less-27 GET - Error Based- All your UNION and select belong to us 过滤了union 和select的报错注入 查看源码: 使用%09 ...

  7. maven 学习---Maven自动化部署

    在项目开发中,通常是部署过程包含以下步骤 检入代码在建项目全部进入SVN或源代码库中,并标记它. 从SVN下载完整的源代码. 构建应用程序. 生成输出要么WAR或EAR文件存储到一个共同的网络位置. ...

  8. 【设计模式】Factory

    前言 这篇博客将包括两种设计模式,一种是工厂模式,一种是抽象工厂模式.不管是哪一种设计模式,本质上在解决的问题是对象创建的问题.工厂,可以是简简单单的一个函数,也可以是一个有具体实现的类,也可以是一个 ...

  9. 高性能TcpServer(C#) - 5.客户端管理

    高性能TcpServer(C#) - 1.网络通信协议 高性能TcpServer(C#) - 2.创建高性能Socket服务器SocketAsyncEventArgs的实现(IOCP) 高性能TcpS ...

  10. ElasticSearch最全分词器比较及使用方法

    介绍:ElasticSearch 是一个基于 Lucene 的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful web 接口.Elasticsearch 是用 Java 开 ...