题意:9*6的地图上每个格子里是一种管道(-,T,L,+型或没有),可以把管道旋转
0
,
90
,
180
,
270
°
0,90,180,270\degree
0,90,180,270°,问地图有几行的右边界与第X行的左边界通过管道相连。
插头DP论文题,注意常数因子对于程序效率的影响。
用1代表带有火的插头,剩下的用最小表示法。
1.不含1的状态可以舍弃。
2.只含一个x的状态(x>=2)可以把x变为0,极度节省状态数。
虽然我的状态定义和论文不一样,但是不加剪枝的情况下,其实所有定义方式的有效状态都是一样的。
AC Code:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int n=9,m=6,mask[15];
char mp[15][15];
set<LL>st[2];
LL encode(int pos)
{
LL ret = 0;
static int id[15]={},cnt,siz[15]={};
memset(siz,0,sizeof siz),memset(id,-1,sizeof id),id[0]=0,id[1]=cnt=1;
for(int i=pos;i>=0;i--)
siz[id[mask[i]]==-1?id[mask[i]]=++cnt:id[mask[i]]]++;
siz[1] = 20 , siz[0] = 20;
for(int i=pos;i>=0;i--)
ret=ret<<4|(siz[id[mask[i]]]==1?0:id[mask[i]]);
if(pos == n-1) ret <<= 4;
return ret;
}
void decode(LL ret){ for(int i=0;i<=n;i++) mask[i]=ret&15,ret>>=4; }
void dp(int i,int j,int now)
{
for(set<LL>::iterator it=st[now^1].begin();it!=st[now^1].end();it++)
{ decode(*it);
bool flag = 0;
for(int k=0;k<=n;k++)
if(mask[k] == 1)
flag = 1;
if(!flag) continue;
if(mp[i][j] == '.')
{
mask[i] = mask[i+1] = 0;
st[now].insert(encode(i==n-1?n-1:n));
}
if(mp[i][j] == '-')
{
int u = mask[i] , v = mask[i+1];
mask[i] = v , mask[i+1] = 0;
st[now].insert(encode(i==n-1?n-1:n));
mask[i+1] = u , mask[i] = 0;
st[now].insert(encode(i==n-1?n-1:n));
}
if(mp[i][j] == '+')
{
int u = mask[i] , v = mask[i+1];
if(u && v)
{
if(u == 1)
{
for(int k=0;k<=n;k++)
if(mask[k]==v)
mask[k]=u;
}
else
for(int k=0;k<=n;k++)
if(mask[k]==u)
mask[k]=v;
}
else if(u || v)
mask[i] = mask[i+1] = u + v;
else
{
mask[i] = mask[i+1] = 13;
}
st[now].insert(encode(i==n-1?n-1:n));
}
if(mp[i][j] == 'L')
{
int u = mask[i] , v = mask[i+1];
mask[i+1] = 0;
st[now].insert(encode(i==n-1?n-1:n));
mask[i] = 0 , mask[i+1] = v;
st[now].insert(encode(i==n-1?n-1:n));
mask[i] = mask[i+1] = 13;
st[now].insert(encode(i==n-1?n-1:n));
if(u && v)
{
if(u == 1)
{
for(int k=0;k<=n;k++)
if(mask[k]==v)
mask[k]=u;
}
else
for(int k=0;k<=n;k++)
if(mask[k]==u)
mask[k]=v;
}
mask[i] = mask[i+1] = 0;
st[now].insert(encode(i==n-1?n-1:n));
}
if(mp[i][j] == 'T')
{
int u = mask[i] , v = mask[i+1];
if(u && v)
{
if(u == 1)
{
for(int k=0;k<=n;k++)
if(mask[k]==v)
mask[k]=u;
}
else
for(int k=0;k<=n;k++)
if(mask[k]==u)
mask[k]=v;
mask[i+1] = 0;
st[now].insert(encode(i==n-1?n-1:n));
decode(*it);
if(u == 1)
{
for(int k=0;k<=n;k++)
if(mask[k]==v)
mask[k]=u;
}
else
for(int k=0;k<=n;k++)
if(mask[k]==u)
mask[k]=v;
mask[i] = 0;
st[now].insert(encode(i==n-1?n-1:n));
decode(*it);
mask[i] = mask[i+1];
st[now].insert(encode(i==n-1?n-1:n));
mask[i] = u;
mask[i+1] = mask[i];
st[now].insert(encode(i==n-1?n-1:n));
mask[i+1] = v;
}
else if(u || v)
{
mask[i] = u+v , mask[i+1] = 0;
st[now].insert(encode(i==n-1?n-1:n));
mask[i+1] = u+v , mask[i] = 0;
st[now].insert(encode(i==n-1?n-1:n));
mask[i] = u , mask[i+1] = v;
if(mask[i]) mask[i+1] = mask[i];
else mask[i+1] = mask[i] = 13;
st[now].insert(encode(i==n-1?n-1:n));
mask[i] = u , mask[i+1] = v;
if(mask[i+1]) mask[i] = mask[i+1];
else mask[i+1] = mask[i] = 13;
st[now].insert(encode(i==n-1?n-1:n));
}
else
{
mask[i] = mask[i+1] = 13;
st[now].insert(encode(i==n-1?n-1:n));
mask[i] = u ,mask[i+1] = v;
st[now].insert(encode(i==n-1?n-1:n));
}
}
}
}
int main()
{
int d;
for(;~scanf("%d",&d);)
{
for(int i=0;i<n;i++) scanf("%s",mp[i]);
memset(mask,0,sizeof mask);
mask[d] = 1;
st[0].clear();
st[0].insert(encode(n));
int now = 1;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
st[now].clear(),dp(j,i,now),now^=1;
int ans = 0;
for(set<LL>::iterator it=st[now^1].begin();it!=st[now^1].end();it++)
{
decode(*it);
int cnt = 0;
for(int k=1;k<=n;k++)
cnt += (mask[k] == 1);
ans = max(ans , cnt);
}
printf("%d\n",ans);
}
}