当前位置: 代码迷 >> 综合 >> 【caioj】1489: 基于连通性状态压缩的 动态规划问题:Formula 1 Ural1519
  详细解决方案

【caioj】1489: 基于连通性状态压缩的 动态规划问题:Formula 1 Ural1519

热度:59   发布时间:2023-10-29 12:58:55.0

今天在TYB大佬的带领下学了一发新姿势啊!!
感觉几年前的省选考过插头DP,就有一点点想学了。。
但是好像以前研究过一小阵子。。
由于没看懂就放弃了。。
然后这次跟着TYB大佬又来了一发。。
感觉还好
感觉这个算法的核心思想就是不断地分类讨论。。
要注意的地方很多。。
然后想学的人还是先看看论文,弄清楚点概念什么的
至于分类讨论,看代码就好
下面是我的代码,有“详细”的注释
哦,还有,学这个东西的时候一定要有纸和笔。。没看懂的地方一定要画。。不要相信什么人脑是无敌的

#include<cstdio>
#include<cstring>
#define ADD add(st,sum)
typedef long long LL;
const int MOD=100037;
const int N=15;
bool map[N][N];//是不是可以走 
int n,m;
int xx=-1,yy;//我们要寻找一个最下 最右的点——>当到他的时候就可以累计答案了
LL ans=0;//答案个数
LL a[2][MOD];//这种状态的数目,其实差不多是来辅助下面的数组 
int b[2][MOD];//状态
int num[2];//状态个数
int HASH[MOD];
/*0:无插头状态 1:左括号插头 2:右括号插头*/
int get (int x,int p)//第j位 当然是四进制里面的第j位啦 
{
   return (x>>(p-1)*2)&3;}
int now=0;
void add (int st,LL sum)//给当前的决策状态加上这个状态
{int ss=st%MOD;while (HASH[ss]!=-1&&b[now][HASH[ss]]!=st){ss++;ss%=MOD;if (ss==0) ss=1;}if (HASH[ss]==-1){HASH[ss]=++num[now];b[now][num[now]]=st;a[now][num[now]]=sum;}else a[now][HASH[ss]]+=sum;
}
void change (int &s,int p,int v)//把s的第p位改为v
{s=s^(get(s,p)<<(p-1)*2);s=s^(v<<(p-1)*2);
}
void solve ()
{a[0][1]=1;num[0]=1;b[0][1]=0;for (int u=1;u<=n;u++){for (int i=1;i<=m;i++)//当前的转移节点,我们要尝试吧这个节点转到下一个{now^=1;num[now]=0;memset(HASH,-1,sizeof(HASH));for (int k=1;k<=num[now^1];k++)//继承上一个轮廓线的状态{int st=b[now^1][k]; LL sum=a[now^1][k];int p=get(st,i);//获得“竖着的”那个插头状态 int q=get(st,i+1);//获得“横着的”那个插头状态 // printf("%d %d %d %d %d %d\n",u,i,k,st,p,q);if (map[u][i]==false)//这个是障碍点{if (p+q==0) ADD;//要是可以把它绕开就好了 continue;}if (p+q==0)//没有连到当前格子{if (map[u][i+1]&&map[u+1][i]){change(st,i,1);change(st,i+1,2);ADD;}}else if (p==0&&q!=0){if (map[u][i+1]==true) ADD;if (map[u+1][i]==true){change(st,i,q);change(st,i+1,0);ADD;}}else if (p!=0&&q==0){if (map[u+1][i]==true) ADD;if (map[u][i+1]==true){change(st,i,0);change(st,i+1,p);ADD;}}else if (p==1&&q==2){if (u==xx&&i==yy)ans+=sum;}else if (p==2&&q==1){change(st,i,0);change(st,i+1,0);ADD;}else if (p==1&&q==1){int top=1;for (int pos=i+2;pos<=m+1;pos++){int temp=get(st,pos);if (temp==1) top++;if (temp==2) top--;if (top==0){change(st,i,0);change(st,i+1,0);change(st,pos,1);ADD;break;}}}else if (p==2&&q==2){int top=1;for (int pos=i-1;pos>0;pos--){int temp=get(st,pos);if (temp==2) top++;if (temp==1) top--;if (top==0){change(st,i,0);change(st,i+1,0);change(st,pos,2);ADD;break;}}}}}for (int i=1;i<=num[now];i++) b[now][i]<<=2;}
}
int main()
{memset(map,false,sizeof(map));scanf("%d%d",&n,&m);for (int u=1;u<=n;u++){char ss[15];scanf("%s",ss+1);for (int i=1;i<=m;i++)if (ss[i]=='.') {xx=u;yy=i;map[u][i]=true;}}if (xx==-1) {
   printf("0");return 0;}solve();printf("%lld\n",ans);return 0;
}
  相关解决方案