终于切了第一道广义路径的题目,也确实感到比较复杂,最小表示法的优势也可以体现出来,因为这题,昨天的澡到现在才洗完,按照小hh的思路,用一条轮廓线记录联通状态,注意这里的轮廓线已经不是m+1啦,因为我们不需要左插头了,每个格子可以插至多4个插头,另外一条轮廓线表示当前的染色状态,这个要m+1因为还要保留左上格子的颜色,然后我们对于4个格子的颜色讨论,左,上,左上,当前,一共16中情况,8种是对称的,同时要注意一种情况,已经轮廓线上部已经有一个单独的联通块。说说我debug这么久是为什么吧,先是cs打成cl,问题是前4个sample尽然过啦,后面的sample爆了,后来发现改之,然后就开始纠结最后一个sample,对不上,一直到今天早上,我拿网上代码对拍,发现m=8的时候结果都不对,其他都是对的,查看代码数遍,直到刚刚,突然意识到,我的状态爆了,我最小表示法用二进制3位表示,范围0~7,我sb的从1开始标号,那么m=8时,12345678最大的标号就是这样,出现了8,坑爹了,改之,果然sample过了,提交1y,刷进了第一版
Ranking | Submission | Run Time | Language | Submission Date |
5 | 10710525 | 0.360 | C++ | 2012-10-10 05:40:30 |
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=10007;
int pre[9][9][maxn];
bool res[9][9][maxn];
int bin[20],code[20];
struct node
{
int size,head[maxn],next[maxn];
LL sta[maxn],clo[maxn],sum[maxn];
void clear()
{
memset(head,-1,sizeof(head));
size=0;
}
void push(LL st,const LL v,LL cs,int x,int y,bool cl,int k)
{
int hash=((st*13)+cs)%maxn;
for(int i=head[hash];i>=0;i=next[i])
{
if(sta[i]==st&&clo[i]==cs)
{
sum[i]+=v;
return ;
}
}
sta[size]=st,clo[size]=cs,sum[size]=v;
res[x][y][size]=cl,pre[x][y][size]=k;
next[size]=head[hash],head[hash]=size++;
}
}dp[2];
LL encode(int m)
{
LL st=0,cnt=0;
memset(bin,-1,sizeof(bin));
for(int i=m-1;i>=0;i--)
{
if(bin[code[i]]==-1)
bin[code[i]]=cnt++;
code[i]=bin[code[i]];
st<<=3;
st|=code[i];
}
return st;
}
void decode(LL st,int m)
{
for(int i=0;i<m;i++)
{
code[i]=st&7;
st>>=3;
}
}
int n,m,now,old;
char gp[20][20];
bool check(LL cs,int x,int y,int m,int nc)
{
int cnt=0,cnt1=0;
for(int i=0;i<m;i++)
{
if(code[i]==code[y])
cnt++;
if(((cs>>i)&1)==(nc^1))
cnt1++;
}
if(cnt==1)
{
if(cnt1>1)
return false;
char ch=nc==1?'o':'#';
for(int i=x-1;i<n;i++)
for(int j=i==x-1?y+1:0;j<m;j++)
{
if(gp[i][j]==ch)
return false;
if(i+1<n&&j+1<m)
return false;
}
}
return true;
}
void DP(int x,int y,int nc)
{
for(int k=0;k<dp[old].size;k++)
{
bool l=y==0?0:((dp[old].clo[k]>>(y-1))&1)==nc;
bool up=x==0?0:((dp[old].clo[k]>>y)&1)==nc;
bool lp=(x==0||y==0)?0:((dp[old].clo[k]>>m)&1)==nc;
decode(dp[old].sta[k],m);
if(x&&!up&&!check(dp[old].clo[k],x,y,m,nc))
continue;
if(!l&&!up&&!lp)
code[y]=10;
else if(l&&!up&&!lp)
code[y]=code[y-1];
else if(!l&&up&&!lp)
code[y]=code[y];
else if(!lp&&l&&up)
{
if(code[y-1]!=code[y])
{
for(int i=0,id=code[y];i<m;i++)
if(code[i]==id)
code[i]=code[y-1];
}
}
else if(lp&&!up&&!l)
{
if(x==n-1&&y==m-1)
continue;
code[y]=10;
}
else if(lp&&l&&!up)
code[y]=code[y-1];
else if(lp&&up&&!l)
code[y]=code[y];
else continue;
LL cs=dp[old].clo[k]&(~(1<<y))&(~(1<<m));
if(nc) cs|=1<<y;
if((up==0&&nc==0)||(up==1&&nc==1)) cs|=1<<m;
dp[now].push(encode(m),dp[old].sum[k],cs,x,y,nc,k);
}
}
void slove()
{
dp[0].clear();
dp[0].push(0,1,0,n,m,0,-1);
now=0,old=1;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
old=now,now^=1,dp[now].clear();
if(gp[i][j]!='#')
DP(i,j,0);
if(gp[i][j]!='o')
DP(i,j,1);
}
int flag=-1,ans=0;
for(int i=0;i<dp[now].size;i++)
{
decode(dp[now].sta[i],m);
int cnt=0;
memset(bin,-1,sizeof(bin));
for(int j=0;j<m;j++)
{
if(bin[code[j]]==-1)
bin[code[j]]=cnt++;
}
if(cnt<=2)
{
flag=i;
ans+=dp[now].sum[i];
}
}
if(flag==-1)
puts("0\n");
else
{
printf("%d\n",ans);
for(int i=n-1;i>=0;i--)
for(int j=m-1;j>=0;j--)
{
gp[i][j]=res[i][j][flag]==0?'o':'#';
flag=pre[i][j][flag];
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
printf("%c",gp[i][j]);
puts("");
}
puts("");
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%s",gp[i]);
}
slove();
}
return 0;
}