BZOJ_2595_[Wc2008]游览计划_斯坦纳树

题意:

分析:

斯坦纳树裸题,有几个需要注意的地方

给出矩阵,不用自己建图,但枚举子集转移时会算两遍,需要减去当前点的权值

方案记录比较麻烦,两边的转移都需要记录,最后dfs找方案会比较容易理解

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
#define N 110
#define LL long long
priority_queue <pair <int,int> >q;
LL map[11][11],dis[1<<10][N];
int chosex[1<<10][N],chosey[1<<10][N];
bool change[1<<10][N];
int flg[11][11];
int n,m;
int tx[]={1,-1,0,0};
int ty[]={0,0,1,-1};
int id[N][N],a[N],xx[N],yy[N],cnt,vis[1<<10][N];
void dfs(int sta,int p){
    if(!dis[sta][p])return ;
    flg[xx[p]][yy[p]]=1;
    if(change[sta][p]){
        dfs(chosex[sta][p],p);
        dfs(chosey[sta][p],p);
    }else dfs(sta,id[chosex[sta][p]][chosey[sta][p]]);
}
int main(){
    scanf("%d%d",&n,&m);
    int i,j,tot=0,k,x;
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            scanf("%lld",&map[i][j]);
            id[i][j]=++tot;
            xx[tot]=i;yy[tot]=j;
            if(!map[i][j]){
                a[++cnt]=tot;
            }
        }
    }
    int mask=(1<<cnt)-1;
    memset(dis,0x3f,sizeof(dis));
    for(i=1;i<=cnt;i++){
        dis[1<<i-1][a[i]]=0;
    }
    for(j=1;j<=mask;j++){
        for(i=1;i<=n*m;i++){
            for(k=j&(j-1);k;k=j&(k-1)){
                if(dis[j][i]>dis[k][i]+dis[j-k][i]-map[xx[i]][yy[i]]){
                    dis[j][i]=dis[k][i]+dis[j-k][i]-map[xx[i]][yy[i]];
                    chosex[j][i]=k,chosey[j][i]=j-k;
                    change[j][i]=1;
                }
                // dis[j][i]=min(dis[j][i],dis[k][i]+dis[j-k][i]-map[xx[i]][yy[i]]);
            }
        }
        for(i=1;i<=n*m;i++){
            q.push(make_pair(-dis[j][i],i));
        }
        while(!q.empty()){
            x=q.top().second;q.pop();
            if(vis[j][x])continue;
            vis[j][x]=1;
            int nx=xx[x],ny=yy[x];
            for(i=0;i<4;i++){
                int dx=nx+tx[i],dy=ny+ty[i];
                if(dx>=1&&dx<=n&&dy>=1&&dy<=m){
                    if(dis[j][id[dx][dy]]>dis[j][x]+map[dx][dy]){
                        dis[j][id[dx][dy]]=dis[j][x]+map[dx][dy];
                        chosex[j][id[dx][dy]]=nx;
                        chosey[j][id[dx][dy]]=ny;
                        change[j][id[dx][dy]]=0;
                        q.push(make_pair(-dis[j][id[dx][dy]],id[dx][dy]));
                    }
                }
            }
        }
    }
    LL ans=1ll<<60;
    int end;
    for(i=1;i<=n*m;i++){
        if(ans>dis[mask][i]){
            ans=dis[mask][i];
            end=i;
        }
        // ans=min(ans,dis[mask][i]);
    }
    dfs(mask,end);
    printf("%lld\n",ans);
    for(i=1;i<=n;i++){
        for(j=1;j<=m;j++){
            if(!map[i][j]){
                printf("x");
            }else if(flg[i][j]){
                printf("o");
            }else printf("_");
        }
        puts("");
    }
}

原文地址:https://www.cnblogs.com/suika/p/8542203.html

时间: 2024-11-18 12:28:39

BZOJ_2595_[Wc2008]游览计划_斯坦纳树的相关文章

【BZOJ2595】【Wc2008】游览计划、斯坦纳树

题解:斯坦纳树,实现神马的在代码里面有还看得过去的注释. 代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 15 #define inf 0x3f3f3f3f using namespace std; const int dx[]={0,0,1,-1}; const int dy[

[WC2008]游览计划 「斯坦那树模板」

斯坦那树 百度释义 斯坦纳树问题是组合优化问题,与最小生成树相似,是最短网络的一种.最小生成树是在给定的点集和边中寻求最短网络使所有点连通.而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小. 即最小斯坦那树即为并非选择所有的结点,而是选择一部分结点,为保证它们连通,且求解最小开销 题解 斯坦那树模板 发现直接表示点的存在性没有意义 设函数 \(f[i][state]\) 表示:对于点 \(i\),其它结点与其连通情况 那么有两种转移 其一.由其子集转移 \[f[i][state

WC 2008 观光计划(斯坦纳树)

题意 https://www.lydsy.com/JudgeOnline/problem.php?id=2595 思路 是一道比较裸的斯坦纳树呢- 题意等价于选出包含一些点的最小生成树,这就是斯坦纳树的功能. 举个例子,给定 \(n\) 个点,其中 \(k\) 个点被称作关键点,\(m\) 条带权边,求原图的一个权值最小的子图,这张子图图为包含这 \(k\) 个点的树. 我们定义 \(dp[i][j]\) 为关键点集合 \(i\) 与任意节点 \(j\) 连通的最小权的树.考虑转移这个 \(dp

BZOJ_4006_[JLOI2015]管道连接_斯坦纳树

题意: 小铭铭最近进入了某情报部门,该部门正在被如何建立安全的通道连接困扰. 该部门有 n 个情报站,用 1 到 n 的整数编号.给出 m 对情报站 ui;vi 和费用 wi,表示情 报站 ui 和 vi 之间可以花费 wi 单位资源建立通道. 如果一个情报站经过若干个建立好的通道可以到达另外一个情报站,那么这两个情报站就 建立了通道连接.形式化地,若 ui 和 vi 建立了通道,那么它们建立了通道连接:若 ui 和 vi 均 与 ti 建立了通道连接,那么 ui 和 vi 也建立了通道连接.

【BZOJ 2595】2595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)

2595: [Wc2008]游览计划 Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 1572  Solved: 739 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数目. 相邻的整数用 (若干个) 空格隔开,行首行末也可能有多余的空格. Output 由 N

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

[BZOJ2595][Wc2008]游览计划 Description Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点:否则表示控制该方块至少需要的志愿者数目. 相邻的整数用 (若干个) 空格隔开,行首行末也可能有多余的空格. Output 由 N + 1行组成.第一行为一个整数,表示你所给出的方案中安排的志愿者总数目. 接下来 N行,每行M 个字符,描述方案中相应方块的情况: z  ‘_’(下划线)表示该

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

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

BZOJ 2595: [Wc2008]游览计划 [DP 状压 斯坦纳树 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 g

BZOJ 2595 Wc2008 游览计划 斯坦纳树

题目大意:给定一个矩阵,有一些关键点,每个格子有权值,选择一些格子使所有关键点连通,求最小权值和 传说中的斯坦纳树- - 感觉不是很难理解的样子 枚举连通的状态,对于每个状态先对每个位置枚举子集进行合并,然后对这个状态的分层图进行SPFA 看了几分代码还是ZKY写的比较简洁- - 此外就是终于能通过操作符重载访问结构体里的三维数组了- - 我真是太丧病了233 #include <cstdio> #include <cstring> #include <iostream>