斯坦纳树板子题。

  考虑状压dp,设f[i][j][S]表示当前在点(i,j)考虑转移,其所在的联通块包含的关键点集(至少)为S的答案。

  转移时首先枚举子集,有f[i][j][S]=min{f[i][j][x]+f[i][j][y]-a[i][j]} (x&y=0,x|y=S)。

  然后考虑从点(i,j)从哪拓展而来,有f[i][j][S]=min{f[x][y][S]}+a[i][j],其中(x,y)为(i,j)的相邻点,使用spfa转移。

  这里第二种转移仅在相同关键点集下进行,因为由更小点集转移而来的情况已在第一种转移中被考虑。

  对于输出方案,记录如何转移而来即可。

  其实并没有搞懂。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 12
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,m,s,a[N][N],id[N][N],f[N][N][<<N],from[N][N][<<N][],q[N*N*N*N][];
int wx[]={,,,-},wy[]={,,-,};
bool flag[N][N];
char b[N][N];
void inc(int &x){x++;if (x>n*m+) x-=n*m+;}
void spfa(int k)
{
int head=,tail=;
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
tail++,q[tail][]=i,q[tail][]=j,flag[i][j]=;
do
{
inc(head);int x=q[head][],y=q[head][];flag[x][y]=;
for (int i=;i<;i++)
{
int u=x+wx[i],v=y+wy[i];
if (u&&u<=n&&v&&v<=m&&f[x][y][k]+a[u][v]<f[u][v][k])
{
f[u][v][k]=f[x][y][k]+a[u][v];
from[u][v][k][]=x,from[u][v][k][]=y;
if (!flag[u][v]) flag[u][v]=,inc(tail),q[tail][]=u,q[tail][]=v;
}
}
}while (head!=tail);
}
void getans(int x,int y,int k)
{
b[x][y]='o';
while (from[x][y][k][]>)
{
int u=from[x][y][k][],v=from[x][y][k][];
b[x=u][y=v]='o';
}
if (from[x][y][k][]<) getans(x,y,-from[x][y][k][]),getans(x,y,-from[x][y][k][]);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj2595.in","r",stdin);
freopen("bzoj2595.out","w",stdout);
#endif
n=read(),m=read();
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
{
a[i][j]=read(),s+=(a[i][j]==);
if (!a[i][j]) id[i][j]=s;
}
memset(f,,sizeof(f));
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
{
f[i][j][]=a[i][j];
if (id[i][j]) f[i][j][<<id[i][j]-]=a[i][j];
}
for (int k=;k<(<<s);k++)
{
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
for (int x=k;x>=(k^x);x=x-&k)
if (f[i][j][x]+f[i][j][k^x]-a[i][j]<f[i][j][k])
{
f[i][j][k]=f[i][j][x]+f[i][j][k^x]-a[i][j];
from[i][j][k][]=-x,from[i][j][k][]=-(k^x);
}
spfa(k);
}
int ans=;
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
ans=min(ans,f[i][j][(<<s)-]);
cout<<ans<<endl;
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
b[i][j]='_';
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
if (f[i][j][(<<s)-]==ans)
{
getans(i,j,(<<s)-);
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
if (!a[i][j]) b[i][j]='x';
for (int i=;i<=n;i++)
{
for (int j=;j<=m;j++)
putchar(b[i][j]);
cout<<endl;
}
return ;
}
}

BZOJ2595 WC2008游览计划(斯坦纳树)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  10. BZOJ2595 Wc2008 游览计划 【斯坦纳树】【状压DP】*

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

随机推荐

  1. xrange 和range的区别

    >>> xrange(5)xrange(5)>>> list(xrange(5))[0, 1, 2, 3, 4]>>> xrange(1,5)xr ...

  2. 一、java三大特性--封装

    封装字面意思即包装.专业点来说就是数据隐藏,是指利用抽象数据将数据和基于数据的操作封装起来,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能的隐藏细节,只保留一些对外的接口和外部 ...

  3. MongoDB的地理位置查询,以及和mysql的使用对比

    MongoDB的一个特色就是具有丰富的查询接口,比如地理位置查询. 在地理位置查询上,MongoDB有着比传统关系型数据库的优势,下面举个例子. 当前移动互联网应用,按用户离目标门店距离排序上的场景很 ...

  4. Linux java 命令行编译 jar包

    Java 命令行编译成class,然后在打包成jar文件. 编译成class javac -classpath $CLASS_PATH -d class ./src/Hello.java 可以通过ja ...

  5. angularjs自定义指令Directive

    今天学习angularjs自定义指令Directive.Directive是一个非常棒的功能.可以实现我们自义的的功能方法. 下面的例子是演示用户在文本框输入的帐号是否为管理员的帐号"Adm ...

  6. Spring Boot Admin 日志查看功能

    按照官方配置POM和配置文件后,能够结合Eureka查看各微服务状态,但是日志始终查看不了,出现406等错误. 最后偶然发现,是在在从官方网站拷贝配置的时候,出现的问题. logging.file=* ...

  7. 【转】单KEY业务,数据库水平切分架构实践

    本文将以“用户中心”为例,介绍“单KEY”类业务,随着数据量的逐步增大,数据库性能显著降低,数据库水平切分相关的架构实践: 如何来实施水平切分 水平切分后常见的问题 典型问题的优化思路及实践 一.用户 ...

  8. C# 多线程 Parallel.For 和 For 谁的效率高?那么 Parallel.ForEach 和 ForEach 呢?

    还是那句话:十年河东,十年河西,莫欺少年穷. 今天和大家探讨一个问题:Parallel.For 和 For 谁的效率高呢? 从CPU使用方面而言,Parallel.For 属于多线程范畴,可以开辟多个 ...

  9. LOJ #559. 「LibreOJ Round #9」ZQC 的迷宫

    一道ZZ结论题,主要是来写一写交互题的. 我们要先知道一句话: 扶着墙是肯定可以走出简单迷宫的. 然后我们冷静分析问题.若这个迷宫是\(n\times m\)的,那么最多有\(2mn+n+m\)个墙壁 ...

  10. nginx的web缓存服务环境部署记录

    web缓存位于内容源Web服务器和客户端之间,当用户访问一个URL时,Web缓存服务器会去后端Web源服务器取回要输出的内容,然后,当下一个请求到来时,如果访问的是相同的URL,Web缓存服务器直接输 ...