斯坦纳树是在一个图中选取某些特定点使其联通(可以选取额外的点),要求花费最小,最小生成树是斯坦纳树的一种特殊情况

我们用dp[i][j]来表示以i为根,和j状态是否和i联通,那么有

转移方程:

dp[i][j]=min(dp[i][s]+dp[j-s]-a[i][j]) (表示有两个状态s和j-s都和i联通,我们把这两个状态联通起来,这样多算了一次a[i][j],减去即可)

dp[i][j]=min(dp[i][j],dp[k][j]+a[i][k]) (如果i和k连着,那么,链接i和k,更新dp[i][j]),此处类似与最短路中的松弛操作

来看这道题就是求平面上给定点的斯坦纳树,要求输出路径,我们更新状态的时候记录pre,

spfa松弛(164 ms):

/**************************************************************
Problem: 2595
User: walfy
Language: C++
Result: Accepted
Time:164 ms
Memory:7756 kb
****************************************************************/ //#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define Max(a, b) ((a)>(b)?(a):(b))
#define Min(a, b) ((a)<(b)?(a):(b))
#define fio ios::sync_with_stdio(false);cin.tie(0)
inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;}
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;} using namespace std; const double g=10.0,eps=1e-12;
const int N=10+10,maxn=(1<<10)+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f; struct Pre{
int x,y,st;
}pre[N][N][maxn];
int f[N][N][maxn],n,m,a[N][N];
queue<pii>q;
bool vis[N][N];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
void spfa(int st)
{
while(!q.empty())
{
pii p=q.front();q.pop();
vis[p.fi][p.se]=0;
for(int i=0;i<4;i++)
{
int nx=p.fi+dx[i],ny=p.se+dy[i];
if(1<=nx&&nx<=n&&1<=ny&&ny<=m)
{
if(f[p.fi][p.se][st]+a[nx][ny]<f[nx][ny][st])
{
f[nx][ny][st]=f[p.fi][p.se][st]+a[nx][ny];
pre[nx][ny][st]={p.fi,p.se,st};
if(!vis[nx][ny])
{
vis[nx][ny]=1;
q.push(mp(nx,ny));
}
}
}
}
}
}
void dfs(int x,int y,int st)
{
vis[x][y]=1;
Pre p=pre[x][y][st];
if(!p.x)return ;
dfs(p.x,p.y,p.st);
if(x==p.x&&y==p.y)
dfs(p.x,p.y,st-p.st);
}
int main()
{
int cnt=0,ansx=-1,ansy;
scanf("%d%d",&n,&m);
memset(f,inf,sizeof f);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(!a[i][j])
{
f[i][j][(1<<cnt)]=0;cnt++;
if(ansx==-1)ansx=i,ansy=j;
}
}
}
for(int st=0;st<(1<<cnt);st++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int s=st;s;s=(s-1)&st)
{
if(f[i][j][s]+f[i][j][st-s]-a[i][j]<f[i][j][st])
{
f[i][j][st]=f[i][j][s]+f[i][j][st-s]-a[i][j];
pre[i][j][st]={i,j,s};
}
}
if(f[i][j][st]<inf)q.push(mp(i,j)),vis[i][j]=1;
}
}
spfa(st);
}
printf("%d\n",f[ansx][ansy][(1<<cnt)-1]);
memset(vis,0,sizeof vis);
dfs(ansx,ansy,(1<<cnt)-1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!a[i][j])putchar('x');
else putchar(vis[i][j]?'o':'_');
}
puts("");
}
return 0;
}
/*********************** ***********************/

dij松弛(432 ms):

/**************************************************************
Problem: 2595
User: walfy
Language: C++
Result: Accepted
Time:432 ms
Memory:7756 kb
****************************************************************/ //#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define Max(a, b) ((a)>(b)?(a):(b))
#define Min(a, b) ((a)<(b)?(a):(b))
#define fio ios::sync_with_stdio(false);cin.tie(0)
inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;}
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;} using namespace std; const double g=10.0,eps=1e-12;
const int N=10+10,maxn=(1<<10)+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f; struct Pre{
int x,y,st;
}pre[N][N][maxn];
int f[N][N][maxn],n,m,a[N][N];
bool vis[N][N];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int state;
struct node{
int x,y;
bool operator <(const node&rhs)const{
return f[x][y][state]<f[rhs.x][rhs.y][state];
}
};
priority_queue<node>q;
void dij(int st)
{
while(!q.empty())
{
node p=q.top();q.pop();
for(int i=0;i<4;i++)
{
int nx=p.x+dx[i],ny=p.y+dy[i];
if(1<=nx&&nx<=n&&1<=ny&&ny<=m)
{
if(f[p.x][p.y][st]+a[nx][ny]<f[nx][ny][st])
{
f[nx][ny][st]=f[p.x][p.y][st]+a[nx][ny];
pre[nx][ny][st]={p.x,p.y,st};
q.push({nx,ny});
}
}
}
}
}
void dfs(int x,int y,int st)
{
vis[x][y]=1;
Pre p=pre[x][y][st];
if(!p.x)return ;
dfs(p.x,p.y,p.st);
if(x==p.x&&y==p.y)
dfs(p.x,p.y,st-p.st);
}
int main()
{ int cnt=0,ansx=-1,ansy;
scanf("%d%d",&n,&m);
memset(f,inf,sizeof f);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(!a[i][j])
{
f[i][j][(1<<cnt)]=0;cnt++;
if(ansx==-1)ansx=i,ansy=j;
}
}
}
for(int st=0;st<(1<<cnt);st++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int s=st;s;s=(s-1)&st)
{
if(f[i][j][s]+f[i][j][st-s]-a[i][j]<f[i][j][st])
{
f[i][j][st]=f[i][j][s]+f[i][j][st-s]-a[i][j];
pre[i][j][st]={i,j,s};
}
}
if(f[i][j][st]<inf)q.push({i,j});
}
}
state=st;
dij(st);
}
printf("%d\n",f[ansx][ansy][(1<<cnt)-1]);
memset(vis,0,sizeof vis);
dfs(ansx,ansy,(1<<cnt)-1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!a[i][j])putchar('x');
else putchar(vis[i][j]?'o':'_');
}
puts("");
}
return 0;
}
/*********************** ***********************/

bzoj2595: [Wc2008]游览计划 斯坦纳树的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. JS实现仿腾讯微博无刷新删除微博效果代码

    这里演示JS仿腾讯微博无刷新删除效果,将显示在微博列表里的内容删除,运用AJAX技术,无刷新删除微博的内容,参考性强,希望对初学AJAX的朋友有所帮助. 在线演示地址如下: http://demo.j ...

  2. 代码静态扫描工具sonar

    一.SonarQube整体介绍 SonarQube为静态代码检查工具,采用B/S架构,帮助检查代码缺陷,改善代码质量,提高开发速度,通过插件形式,可以支持Java.C.C++.JavaScripe等等 ...

  3. 20145206邹京儒MSF基础应用

    20145206邹京儒MSF基础应用 一.MS08_067漏洞渗透攻击实践 实验前准备 1.两台虚拟机,其中一台为kali,一台为windows xp sp3(英文版). 2.在VMware中设置两台 ...

  4. 20145334赵文豪《网络攻防》 MSF基础应用

    实践目标 掌握metasploit的基本应用方式 掌握常用的三种攻击方式的思路. 实验要求 一个主动攻击,如ms08_067 一个针对浏览器的攻击,如ms11_050 一个针对客户端的攻击,如Adob ...

  5. Java中的三大框架分别有什么用

    一.Spring Spring是一个解决了许多在J2EE开发中常见的问题的强大框架. Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯.Spring的架构基础是 ...

  6. [算法整理]树上求LCA算法合集

    1#树上倍增 以前写的博客:http://www.cnblogs.com/yyf0309/p/5972701.html 预处理时间复杂度O(nlog2n),查询O(log2n),也不算难写. 2#st ...

  7. 多态时最好将基类的析构函数设为virtual、 C++中两个类相互包含引用问题 (转载)

    多态:http://blog.csdn.net/tmljs1988/article/details/8146521 C++中两个类相互包含引用问题:http://blog.csdn.net/leo11 ...

  8. 【第十二章】 springboot + mongodb(复杂查询)

    简单查询:使用自定义的XxxRepository接口即可.(见 第十一章 springboot + mongodb(简单查询)) 复杂查询:使用MongoTemplate以及一些查询条件构建类(Bas ...

  9. Unity 之 图片显示的真实大小

    图片放入Unity中自身的属性 在做帽子游戏的时候,看到这么一段代码 //获取保龄球的自身宽度 float ballWidth=ball.GetComponent<Renderer>(). ...

  10. Unity3D学习笔记(六):三角函数和点乘

    三角函数: 概念:用来描述三角形中某个角和对应的三条边的比例关系. 正弦:sin<θ>(sin<theta>)=对边/斜边 余弦:cos<θ>(cos<the ...