BZOJ 2595 游览计划(插头DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2595

题意:给出一个数字矩阵。求一个连通块包含所有的数字0且连通块内所有数字之和最小。

思路:对于每个格子,是0则必须要选。那么对于不选的格子(i,j)在什么时候可以不选呢?必须同时满足以下两个条件:

(1)(i,j)不是0;

(2)(i-1,j)不选或者(i-1,j)选了但是轮廓线上还有别的地方与(i-1,j)是一个连通块。

int Pre[105][N],op[105][N];

struct node
{
    int head[mod],next[N],e,st[N],val[N];

    void init()
    {
        clr(head,-1); e=0;
    }

    void add(int S,int K,int preSt,int flag,int t)
    {
        int x=S%mod;
        int i;
        for(i=head[x];i!=-1;i=next[i])
        {
            if(st[i]==S)
            {
                if(K<val[i])
                {
                    val[i]=K;
                    Pre[t][i]=preSt;
                    op[t][i]=flag;
                }
                return;
            }
        }
        Pre[t][e]=preSt;
        op[t][e]=flag;

        st[e]=S; val[e]=K; next[e]=head[x];
        head[x]=e++;
    }
};

node f[2];
int pre,cur,a[15][15],n,m;
int S[15];

void decode(int st)
{
    int i;
    for(i=0;i<m;i++) S[i]=st&7,st>>=3;
}

int incode()
{
    int x=0,i,t=1;
    int mp[8];
    FOR0(i,8) mp[i]=-1;
    mp[0]=0;
    for(i=m-1;i>=0;i--)
    {
        if(mp[S[i]]==-1) mp[S[i]]=t++;
        S[i]=mp[S[i]];
        x=(x<<3)|S[i];
    }
    return x;
}

void tran(int x,int y)
{
    int i;
    for(i=0;i<m;i++) if(S[i]==y) S[i]=x;
}

void DP(int i,int j,int flag)
{
    int x,y,k,t,st,cost,r=i*m+j;
    int num,temp;
    for(k=0;k<f[pre].e;k++)
    {
        st=f[pre].st[k];
        cost=f[pre].val[k];

        decode(st);
        x=j==0?0:S[j-1];
        y=i==0?0:S[j]; 

        if(!flag)
        {
            num=0;
            FOR0(t,m) if(S[t]==y) num++;
            if(S[j]==0||num>1)
            {
                temp=S[j]; S[j]=0;
                f[cur].add(incode(),cost,k,0,r);
                S[j]=temp;
            }
        }

        if(x&&y) tran(x,y);
        else if(x||y) S[j]=x+y;
        else S[j]=7;
        f[cur].add(incode(),cost+a[i][j],k,1,r);
    }
}

char str[15][15];

void DFS(int k,int x)
{
    int i=x/m,j=x%m;
    if(op[x][k]) str[i][j]=a[i][j]?‘o‘:‘x‘;
    else str[i][j]=‘_‘;
    if(x<0) return;
    DFS(Pre[x][k],x-1);
}

int main()
{
    RD(n,m);
    int i,j;
    FOR0(i,n) FOR0(j,m) RD(a[i][j]);
    pre=0; cur=1;
    f[pre].init(); f[pre].add(0,0,0,0,0);
    FOR0(i,n) FOR0(j,m)
    {
        f[cur].init();
        if(a[i][j]) DP(i,j,0);
        else DP(i,j,1);
        swap(cur,pre);
    }
    int ans=INF,last;
    FOR0(i,f[pre].e)
    {
        decode(f[pre].st[i]);
        FOR0(j,m) if(S[j]>1) break;
        if(j>=m&&f[pre].val[i]<ans)
        {
            ans=f[pre].val[i];
            last=i;
        }
    }
    PR(ans); DFS(last,n*m-1);
    FOR0(i,n) str[i][m]=0,puts(str[i]);
}

BZOJ 2595 游览计划(插头DP),布布扣,bubuko.com

时间: 2024-10-01 04:44:57

BZOJ 2595 游览计划(插头DP)的相关文章

BZOJ 2331 地板(插头DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2331 题意:给出一个n*m的地面.有些是障碍.用L型的地板砖铺满.有多少种方案. 思路:用0表示没有插头,用1表示有插头且可以拐弯,用3表示有插头但是不能再拐弯了. 设有m列,轮廓线为[0,m].对于格子(i,j),设左插头x上插头y,那么转移有: (1)x=0,y=0:此时如图1-0,有三种转移,分别是1-1,1-2,1-3; (2)x!=0,y!=0:此时只有当x=y=1时可以转移

bzoj 2331: [SCOI2011]地板 插头dp

用四进制表示状态. 用hash表把一个四进制数映射到一个小数上. 这样就可以memset了. 转移的时候分类讨论一下,特判下边界情况. 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdio> 5 #define bq 1<<bit[j] 6 #define bp 1<<bit[j-1] 7 using namespace std

【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

【BZOJ】【2595】【WC2008】游览计划

Orz zky神犇http://blog.csdn.net/iamzky/article/details/42029921 spfa的灵活应用!(好像是求了一个叫做斯坦纳树的东西……) o(︶︿︶)o 唉我就是太水了,离散化写跪了,x*1e5+y*1e4+k,但是这题里我x和y的范围是[1,10]所以在y==10的时候会出错!! 1 //BZOJ 2595 2 #include<queue> 3 #include<cmath> 4 #include<cstdio> 5

bzoj 1187: [HNOI2007]神奇游乐园 插头dp

1187: [HNOI2007]神奇游乐园 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 668  Solved: 337[Submit][Status][Discuss] Description 经 历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游 乐场,专为旅途中疲惫的人设计.娱乐场可以看成是一块大小为n×m的区域,且这个n×m的区域被分成n×m个

【题解】互不侵犯 SCOI 2005 BZOJ 1087 插头dp

以前没学插头dp的时候觉得这题贼难,根本不会做,学了才发现原来是一裸题. 用二进制表示以前的格子的状态,0表示没放国王,1表示放了国王. 假设当前位置为(x,y),需要记录的是(x-1,y-1)至(x,y-1)的信息,共n+1个点. 每个状态有两种决策,第一种是这个格子不放国王,直接转移. 第二种是这个格子放国王,需要满足几个条件才能进行这步转移,条件很显然,具体见代码和注释. 因为状态数很少,所以也用不到BFS转移状态和Hash的技巧,所以这题还是很清真的,细节不多,码量也很小. #inclu

【BZOJ】2331: [SCOI2011]地板 插头DP

[题意]给定n*m的地板,有一些障碍格,要求用L型的方块不重不漏填满的方案数.L型方块是从一个方格向任意两个相邻方向延伸的方块,不能不延伸.n*m<=100. [算法]插头DP [题解]状态0表示无插头,1表示能拐弯的插头,2表示不能拐弯的插头.(有插头,方块就必须必须延伸到该格),考虑转移即可. 注意可以凭空产生一个能拐弯的插头. n*m<=100,当m>10的时候将i,j互换. #include<cstdio> #include<cstring> #inclu

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数

[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