斯坦纳树板子题。

  考虑状压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. B Long Path

    有n+1个房间.从1-n个房间.每个房间有两扇门.一扇去i+1的房间另一扇去编号为pi的房间. 起点为1,终点为n+1,对应第i个各点,如果我奇数次到达,那么下一步走到a[i]的位子,如果是偶数次到达 ...

  2. Python崛起:“人生苦短,我用Python”并非一句戏言

      这些年,编程语言的发展进程很快,在商业公司.开源社区两股力量的共同推动下,涌现出诸如Go.Swift这类后起之秀,其中最为耀眼的是Python.   在这里还是要推荐下我自己建的Python开发学 ...

  3. C++模板的特化

    C++类模板的三种特化,讲得比较全面 By SmartPtr(http://www.cppblog.com/SmartPtr/) 针对一个模板参数的类模板特化的几种类型, 一是特化为绝对类型(全特化) ...

  4. UOJ347 WC2018 通道 边分治、虚树

    传送门 毒瘤数据结构题qwq 设三棵树分别为$T1,T2,T3$ 先将$T1$边分治,具体步骤如下: ①多叉树->二叉树,具体操作是对于每一个父亲,建立与儿子个数相同的虚点,将父亲与这些虚点穿成 ...

  5. CF1060D Social Circle 排序

    题目传送门:http://codeforces.com/problemset/problem/1060/D 题意:有$N$个人,你要让他们坐成若干个圆环.他们每个人需要坐一把椅子,左手边至少要有$l_ ...

  6. Cordova套网站

    用Cordova套网站,只修改Content的话,打包后的App,在点击后会打开浏览器,并没有在App中显示内容. 需要设置allow-navigation为 * <?xml version=' ...

  7. cssie7.0兼容

    http://www.w3dev.cn/article/20140328/IE7-float-left-touch-border-inner-break.aspx

  8. 01-时间复杂度、对数器(python)、冒泡、选择、递归实质、归并、小和问题、逆序对、mid

    1.时间复杂度 常数时间的操作:一个操作如果和数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作. 时间复杂度为一个算法流程中,常数操作数量的指标.常用O(读作big O)来表示. 具体来说, ...

  9. koa2入门(2) koa-router 路由处理

    项目地址:https://github.com/caochangkui/demo/tree/koa-test 1. 创建项目 创建目录 koa-test npm init 创建 package.jso ...

  10. 【持续更新中···】Linux下的小技巧

    1.Linux回到上级文件的命令: cd ..回到上一级目录(注意:cd 和..中间有空格) cd ~回到home目录 cd -回到某一目录