BZOJ 2595: [Wc2008]游览计划 [DP 状压 斯坦纳树 spfa]【学习笔记】
2017-03-07 18:10
507 查看
传送门
题意:略
论文 《SPFA算法的优化及应用》
http://www.cnblogs.com/lazycal/p/bzoj-2595.html
本题的核心就是求斯坦纳树:
the Steiner tree problem in graphs requires a tree of minimum weight that contains all terminals (but may include additional vertices).
也就是对于给定的点集求一颗包含他的最小生成树(可以包含额外的点)
$ST$是$NPC$问题,规模小的情况可以使用状压$DP$解决
$f[i][s]$表示根在$i$,连通的点集为$s$的(仅包括给定点集中的点)的最小花费
有两种转移:
对于点权的情况(边权类似):
$f[i][s]=min{f[i][s']+f[i][s-s']-val[i]}$,划分成两个子集,具有阶段性普通$DP$就可以
$f[i][s]=min{f[i'][s]+val[i]}$,从一颗树扩展而来,阶段性不明显,但满足三角不等式,使用$spfa$求解
那么过程就很清楚了
从小到大枚举集合和点
第一种转移枚举子集
第二种转移对当前集合使用spfa
然后就到黄学长哪里仿写了份模板
题意:略
论文 《SPFA算法的优化及应用》
http://www.cnblogs.com/lazycal/p/bzoj-2595.html
本题的核心就是求斯坦纳树:
Steiner Tree:
Given an undirected graph with non-negative edge weights and a subset of vertices, usually referred to as terminals,the Steiner tree problem in graphs requires a tree of minimum weight that contains all terminals (but may include additional vertices).
也就是对于给定的点集求一颗包含他的最小生成树(可以包含额外的点)
$ST$是$NPC$问题,规模小的情况可以使用状压$DP$解决
$f[i][s]$表示根在$i$,连通的点集为$s$的(仅包括给定点集中的点)的最小花费
有两种转移:
对于点权的情况(边权类似):
$f[i][s]=min{f[i][s']+f[i][s-s']-val[i]}$,划分成两个子集,具有阶段性普通$DP$就可以
$f[i][s]=min{f[i'][s]+val[i]}$,从一颗树扩展而来,阶段性不明显,但满足三角不等式,使用$spfa$求解
那么过程就很清楚了
从小到大枚举集合和点
第一种转移枚举子集
第二种转移对当前集合使用spfa
然后就到黄学长哪里仿写了份模板
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; #define pii pair<int,int> #define MP make_pair #define fir first #define sec second typedef long long ll; const int N=12,S=(1<<10)+5,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,m,k,a ; int f [S]; struct Path{ int i,j,s; Path(){} Path(int a,int b,int c):i(a),j(b),s(c){} }pre [S]; queue<pii> q; bool inq ; int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1}; void spfa(int s){ while(!q.empty()){ int x=q.front().fir,y=q.front().sec; inq[x][y]=0;q.pop(); for(int k=0;k<4;k++){ int i=x+dx[k],j=y+dy[k]; if(i<1||i>n||j<1||j>m) continue; if(f[i][j][s]>f[x][y][s]+a[i][j]){ f[i][j][s]=f[x][y][s]+a[i][j]; pre[i][j][s]=Path(x,y,s); if(!inq[i][j]) q.push(MP(i,j)),inq[i][j]=1; } } } } bool vis ; void dfs(int x,int y,int s){ vis[x][y]=1; Path t=pre[x][y][s]; if(t.i==0&&t.j==0) return; dfs(t.i , t.j , t.s); if(t.i==x && t.j==y) dfs(t.i , t.j , s-t.s); } int main(){ freopen("in","r",stdin); n=read();m=read(); memset(f,0x3f,sizeof(f)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ a[i][j]=read(); if(!a[i][j]) f[i][j][1<<k]=0,k++; } int All=1<<k; for(int sa=0;sa<All;sa++){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ for(int s=sa&(sa-1);s;s=sa&(s-1)){ int _=f[i][j][s]+f[i][j][sa-s]-a[i][j]; if(_<f[i][j][sa]){ f[i][j][sa]=_; pre[i][j][sa]=Path(i,j,s); } } if(f[i][j][sa]<INF) q.push(MP(i,j)),inq[i][j]=1; } spfa(sa); } int x=0,y=0,flag=0; for(int i=1;i<=n&&!flag;i++) for(int j=1;j<=m;j++) if(!a[i][j]) {x=i;y=j;flag=1;break;} dfs(x,y,All-1); printf("%d\n",f[x][y][All-1]); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(a[i][j]==0) putchar('x'); else if(vis[i][j]) putchar('o'); else putchar('_'); } puts(""); } }
相关文章推荐
- bzoj2595 [Wc2008]游览计划(最小斯坦纳树(状压DP))
- BZOJ.2595.[WC2008]游览计划(DP 斯坦纳树)
- BZOJ2595:[Wc2008]游览计划——题解(插头dp)
- 斯坦纳树 [bzoj2595][wc2008]游览计划 题解
- bzoj2595 游览计划 斯坦纳树&状压Dp
- 【bzoj2595】[Wc2008]游览计划 斯坦纳树
- BZOJ 2595 [Wc2008]游览计划 ——斯坦纳树
- bzoj 2595: [Wc2008]游览计划(斯坦纳树)
- 【BZOJ2595】【Wc2008】游览计划、斯坦纳树
- BZOJ 2595: [Wc2008]游览计划 斯坦纳树
- bzoj 2595 [Wc2008]游览计划(斯坦纳树)
- BZOJ 2595 Wc2008 游览计划 斯坦纳树
- [BZOJ]2595 [WC2008] 游览计划 斯坦纳树
- BZOJ 2595 [Wc2008]游览计划 SPFA+斯坦纳树 or 插头DP
- 【bzoj2595】[Wc2008]游览计划 斯坦纳树
- BZOJ 2595: [Wc2008]游览计划(斯坦纳树)
- [BZOJ2595][Wc2008]游览计划(斯坦纳树)
- BZOJ_2595_[Wc2008]游览计划_斯坦纳树
- BZOJ 2595 WC 2008 游览计划 斯坦纳树
- 【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)