4月真是没写啥题,这题还是月初写的……

不错的插头dp,首先由n和m的范围知肯定是轮廓线是横向划的

问题的难点在于怎么处理下面两个问题

1.怎么处理独立插头

2.怎么处理完全将W和L左右隔开

先说独立插头,一开始我是增加独立插头位来处理的,一直wa……

后来意识到,因为独立插头一定是在第一行和最后一行唯一的,那么假定最顶部有m中状态,每种状态是一个位子上右下插头,最后一行类似处理,这样就解决了

完全将W和L左右隔开比较简单,这要看当前如果是W,则这个格子左边的下插头一定是偶数个,是L则为奇数个,画个图即可理解。

感觉自己插头dp的代码能力还是不足啊

 #include<bits/stdc++.h>

 using namespace std;
typedef long long ll;
const int mo=;
const int maxl=;
char s[];
int n,m,ans,en,p,a[][],v[],b[],c[]; struct node{
int p[mo],nex[maxl],len,f[maxl];
ll st[maxl];
void clr()
{
len=; memset(p,,sizeof(p));
}
void push(ll nw,int s)
{
int x=nw%mo;
for (int i=p[x];i!=-; i=nex[i])
if (st[i]==nw)
{
f[i]=min(f[i],s);
return;
}
st[++len]=nw; f[len]=s;
nex[len]=p[x]; p[x]=len;
}
} h[]; void get(ll st)
{
for (int i=m; i>=; i--)
{
c[i]=st&;
st>>=;
}
} ll put()
{
memset(v,,sizeof(v)); v[]=;
ll st=; int t=;
for (int i=; i<=m; i++)
{
if (v[b[i]]==-) v[b[i]]=++t;
b[i]=v[b[i]];
st<<=; st|=b[i];
}
return st;
} void shift()
{
for (int i=m;i; i--) b[i]=b[i-];
b[]=;
} int check(int j)
{
int f=;
for (int i=; i<=j; i++)
f+=(c[i]>);
return f;
} void dp(int i,int j)
{
for (int k=; k<=h[p^].len; k++)
{
ll st=h[p^].st[k];
get(st); int pw=h[p^].f[k];
int x=c[j-],y=c[j];
memcpy(b,c,sizeof(b));
if (a[i][j]>=)
{
if (x&&y)
{
if (x==y) continue;
b[j-]=b[j]=;
for (int r=; r<=m; r++)
if (b[r]==x) b[r]=y;
if (j==m) shift();
h[p].push(put(),pw+a[i][j]);
continue;
}
else if (x||y)
{
int r=x+y;
if (a[i][j+]>=)
{
b[j]=r; b[j-]=;
h[p].push(put(),pw+a[i][j]);
}
if (a[i+][j]>=||(i==n&&!check(j-)))
{
b[j]=; b[j-]=r;
if (j==m) shift();
h[p].push(put(),pw+a[i][j]);
}
}
else {
if (a[i][j+]>=&&(a[i+][j]>=||(i==n&&!check(j-))))
{
b[j]=b[j-]=m+;
h[p].push(put(),pw+a[i][j]);
}
b[j]=b[j-]=;
if (j==m) shift();
h[p].push(put(),pw);
}
}
else {
if (a[i][j]==-)
{
if (j==m) shift();
h[p].push(put(),pw);
continue;
}
int sd=check(j-);
if (!(sd&)&&a[i][j]==-) continue;
if (sd&&&a[i][j]==-) continue;
if (j==m) shift();
h[p].push(put(),pw);
}
}
} int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
while (scanf("%d%d",&n,&m)!=EOF)
{
memset(a,,sizeof(a));
for (int i=; i<=n; i++)
{
scanf("%s",s+);
for (int j=; j<=m; j++)
{
int x=-;
if (s[j]=='#') x=-;
else if (s[j]=='W') x=-;
else if (s[j]=='L') x=-;
else x=s[j]-'';
a[i][j]=x;
}
}
ans=1e9+;
h[].clr(); h[].clr(); p=;
for (int i=; i<=m; i++)
if (a[][i]>=)
{
memset(b,,sizeof(b)); b[i]=;
h[].push(put(),);
}
for (int i=; i<=n; i++)
for (int j=; j<=m; j++)
{
p^=; h[p].clr();
dp(i,j);
// cout <<h[p].len<<" "<<i<<" "<<j<<endl;
}
for (int k=; k<=h[p].len; k++)
{
get(h[p].st[k]);
int sd=check(m);
if (sd==) ans=min(ans,h[p].f[k]);
}
if (ans==) puts("-1"); else printf("%d\n",ans);
}
}

hdu4796的更多相关文章

随机推荐

  1. mysql四-2:多表查询

    一 介绍 本节主题 多表连接查询 复合条件连接查询 子查询 准备表 #建表 create table department( id int, name varchar(20) ); create ta ...

  2. Qt ------ QString 操作

    QStringList QString::arg     ------- 字符串的格式化处理,类始于sprintf 比如:QString("%1").arg(10,2,16,QLa ...

  3. socket--粘包

    参考博客:http://www.cnblogs.com/kex1n/p/6502002.html 一.粘包现象 在上一篇的socket传输大数据文章中,我们可以顺利的接发数据,似乎做的不错,可以接收了 ...

  4. HDU 1333 基础数论 暴力

    定义一种数位simth数,该数的各位之和等于其所有质因子所有位数字之和,现给出n求大于n的最小该种数,n最大不超过8位,那么直接暴力就可以了. /** @Date : 2017-09-08 14:12 ...

  5. bzoj 2844: albus就是要第一个出场 高斯消元

    LINK 题意:看题目不如看样例解释.给出有n个数的集合,对这些子集中的数求异或,升序统计所有子集得到的数(重复会被计入),询问一个数x,问这个数出现的第一个位置 思路:在这里要求一个所有可能出现的异 ...

  6. Dubbo 管理控制台安装

    Dubbo 管理控制台官网下载  https://github.com/alibaba/dubbo Dubbo 管控台可以对注册到 zookeeper 注册中心的服务或服务消费者进行管理,而且管控台是 ...

  7. 转【非容器化Jenkins连接Kubernetes】

    一.环境说明 OS系统版本:Ubuntu 18.04 TLS 软件版本:Jenkins 2.121.2                Kubernetes plugin 1.10.2          ...

  8. jquery-load()方法

    调用load方法的完整格式是:load( url, [data], [callback] ), 其中: •url:是指要导入文件的地址. •data:可选参数:因为Load不仅仅可以导入静态的html ...

  9. 如何关闭sublime更新提示

    前提:sublime已激活

  10. 蓝色简洁的企业cms网站权限后台管理模板——后台

    链接:http://pan.baidu.com/s/1pKUqbBd 密码:nink