[Wc2008]游览计划

2595: [Wc2008]游览计划

Time Limit: 10 Sec  Memory Limit: 256 MBSec  Special Judge
[Submit][Status][Discuss]

Description

Input

第一行有两个整数,N和 M,描述方块的数目。 
接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点;
否则表示控制该方块至少需要的志愿者数目。 相邻的整数用 (若干个) 空格隔开,
行首行末也可能有多余的空格。

Output

由 N + 1行组成。第一行为一个整数,表示你所给出的方案
中安排的志愿者总数目。 
接下来 N行,每行M 个字符,描述方案中相应方块的情况: 
z  ‘_’(下划线)表示该方块没有安排志愿者; 
z  ‘o’(小写英文字母o)表示该方块安排了志愿者; 
z  ‘x’(小写英文字母x)表示该方块是一个景点; 
注:请注意输出格式要求,如果缺少某一行或者某一行的字符数目和要求不
一致(任何一行中,多余的空格都不允许出现) ,都可能导致该测试点不得分。

Sample Input

4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0

Sample Output

6
xoox
___o
___o
xoox

HINT

对于100%的数据,N,M,K≤10,其中K为景点的数目。输入的所有整数均在[0,2^16]的范围内

Source

Ljcc930提供SPJ

斯坦纳树

#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#define N 1<<10
using namespace std;
int n,m,sum;
int f[11][11][N+1],g[N+1],a[12][12];
bool v[10000],vis[11][11];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
struct node
{
    int xx,yy,st;
}pre[11][11][N];
queue<int>q;
void dfs(int i,int j,int s)
{

    if(!pre[i][j][s].st) return;
    vis[i][j]=true;
    dfs(pre[i][j][s].xx,pre[i][j][s].yy,pre[i][j][s].st);
    if(pre[i][j][s].xx==i && pre[i][j][s].yy==j)  dfs(i,j,s^pre[i][j][s].st);
}
int main()
{
    memset(f,0x3f3f3f3f,sizeof(f));
    scanf("%d%d",&n,&m);
    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<<sum++]=0;
        }
    int h,l,now,oo=f[0][0][0],x,y;
    for(int S=1;S<(1<<sum);S++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                for(int T=S-1;T;T=(T-1)&S)
                {
                    if(f[i][j][T]+f[i][j][T^S]-a[i][j]<f[i][j][S])
                    {
                        f[i][j][S]=f[i][j][T]+f[i][j][T^S]-a[i][j];
                        pre[i][j][S]=node{i,j,T};
                    }
                }
                if(f[i][j][S]<oo) q.push(i*100+j),v[i*100+j]=true;
            }
        }
        while(!q.empty())
        {
            now=q.front(); q.pop(); v[now]=false;
            h=now/100; l=now%100;
            for(int j=0;j<4;j++)
            {
                x=h+dx[j]; y=l+dy[j];
                if(x<1||x>n||y<1||y>m) continue;
                if(f[x][y][S]>f[h][l][S]+a[x][y])
                {
                    f[x][y][S]=f[h][l][S]+a[x][y];
                    pre[x][y][S]=node{h,l,S};
                    if(!v[x*100+y])
                    {
                        q.push(x*100+y);
                        v[x*100+y]=true;
                    }
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
      for(int j=1;j<=m;j++)
        if(!a[i][j])
        {
            printf("%d\n",f[i][j][(1<<sum)-1]);
            dfs(i,j,(1<<sum)-1);
            for(int h=1;h<=n;h++)
            {
                for(int l=1;l<=m;l++)
                 if(!a[h][l]) putchar(‘x‘);
                 else if(vis[h][l]) putchar(‘o‘);
                 else putchar(‘_‘);
                puts("");
            }
            return 0;
        }
}
时间: 2024-08-09 06:34:42

[Wc2008]游览计划的相关文章

【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  ‘_’(下划线)表示该

bzoj2595 [Wc2008]游览计划

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2595 [题解] 斯坦纳树模板题.学了一发斯坦纳树. 对于一般的斯坦纳树,是 给出一些点和一些关键点和边,要求选择权值和最小的连通块使得关键点连通. 那么一般我们用f(x,status)表示在x,状态为status的最小权值和. 本题我们采用f(i,j,status)表示在(i,j),状态为status的最小权值和. 一开始权值就是题目给的,如果是景点那么在对应的标号的status赋值即可.

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>

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

题意: 分析: 斯坦纳树裸题,有几个需要注意的地方 给出矩阵,不用自己建图,但枚举子集转移时会算两遍,需要减去当前点的权值 方案记录比较麻烦,两边的转移都需要记录,最后dfs找方案会比较容易理解 代码: #include <stdio.h> #include <string.h> #include <algorithm> #include <queue> using namespace std; #define N 110 #define LL long l

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

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

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

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