【矩阵优化连通性状压dp】哈密尔顿路径

来源:互联网 发布:mac怎么新建html文件 编辑:程序博客网 时间:2024/04/29 06:26

以前觉得插头dp好晕啊,结果稍微推了一下转移发现并不难推,只是转移多了点罢了,可是noip模拟的时候270行的恶心转移dp都打过,100+的状压也就还好了。
本题有一维特别大,于是我们压缩小的那一维,然后裸转一行后,用矩阵加速即可。
转移第一次写会觉得麻烦,最后自己推一边在跟别人推的对一下检查有没有漏转或多转,至于要一模一样则没必要,我完全是按自己的喜好来的。
ural有道题是有障碍的哈密尔顿回路,可以拿来练手,注意答案要在最后一个非障碍点统计。
状态比较难记,所以用了hash,也方便预处理

#include <cstdio>#include <cstdlib>#include <cstring>const int mo=1000003,nno=7777777;struct jz {int w[150][150];} f;int n,m,ss,s1,r,ans;int next[mo+mo],w[mo+mo],id[mo+mo],st[2000],net[2000][20],prim[50],ts[50];inline int hash(int s){  int h=s%mo,r,i,ne;  for (;next[h]!=0;) {    h=next[h];    if (w[h]==s) return id[h];  }  ss++,next[h]=ss,w[ss]=s,id[ss]=++s1;  for (r=0,i=1;s;i++,s>>=2) {    ne=s&3;    if (2==ne) ts[++r]=i;    else if (1==ne) net[s1][ts[r]]=i,net[s1][i]=ts[r],r--;  }  return s1;}inline void swap(int &ne,int ns,int yy){  int a=(ns>>yy)&3,b=(ns>>yy-2)&3;  ne=(ns & prim[(yy>>1)]) & prim[(yy>>1)-1];  ne=(ne | (b<<yy)) | (a<<yy-2);}inline void replace(int lo,int &ne,int a){  lo=(lo-1)<<1;  ne=ne & prim[lo>>1];  ne=ne | (a<<lo);}inline void dfs2(int x,int s,int ns){  int nv,v,yy,ne;  if (x==n) {    ns>>=2;nv=hash(ns);v=hash(s);    f.w[v][nv]+=1;    return ;  }  yy=(n-x)<<1;  if ((0==((ns>>yy)&3))&&(0==((ns>>yy-2)&3))) {    if (x==n-1) return ;    ne=(ns | (1<<yy)) | (2<<yy-2);    dfs2(x+1,s,ne);  }  else if ((0==((ns>>yy)&3))||(0==((ns>>yy-2)&3))) {    if (0==((ns>>yy-2)&3)) {      if (x!=n-1) swap(ne,ns,yy),dfs2(x+1,s,ne);      dfs2(x+1,s,ns);    }    else {      swap(ne,ns,yy),dfs2(x+1,s,ne);      if (x!=n-1) dfs2(x+1,s,ns);    }  }  else {    ne=(ns & prim[yy>>1]) & (prim[(yy>>1)-1]);    nv=hash(ns);    if ((1==((ns>>yy)&3))&&(2==((ns>>yy-2)&3)))       if ((!ne)&&(x==n-1)) dfs2(x+1,s,ne);    if ((2==((ns>>yy)&3))&&(1==((ns>>yy-2)&3))) dfs2(x+1,s,ne);    if ((1==((ns>>yy)&3))&&(1==((ns>>yy-2)&3)))       replace(net[nv][(yy>>1)],ne,1),dfs2(x+1,s,ne);    if ((2==((ns>>yy)&3))&&(2==((ns>>yy-2)&3)))      replace(net[nv][(yy>>1)+1],ne,2),dfs2(x+1,s,ne);  }}inline void dfs(int x,int sum,int s){  int ns;  if (sum<0) return ;  if (x>n+1) {    if (0==sum) st[++r]=s,hash(s);return ;}  ns=(s<<2)+1,dfs(x+1,sum+1,ns);  ns=(s<<2)+2,dfs(x+1,sum-1,ns);  ns=(s<<2),dfs(x+1,sum,ns);}void origin(){  int i,j;  r=0;  dfs(2,0,0);  prim[0]=((1<<31)-1)-3;  for (i=1;i<=10;i++) {    prim[i]=1;    for (j=i*2+2;j<=25;j++) prim[i]=(prim[i]<<1)+1;    prim[i]<<=2;    for (j=1;j<=i*2;j++) prim[i]=(prim[i]<<1)+1;  }}inline void mul(jz &a,jz x,jz y){  int i,j,k;  memset(a.w,0,sizeof(a.w));  for (i=1;i<=r;i++)    for (j=1;j<=r;j++)      for (k=1;k<=r;k++)        a.w[i][j]=(a.w[i][j]+(long long)x.w[i][k]*y.w[k][j])%nno;}void fgm(jz &f,jz b,int e){  for (e-=1;e;e>>=1) {    if (1==(e&1)) mul(f,f,b);    mul(b,b,b);  }}void init(){  int i,s,j;  scanf("%d%d\n",&n,&m);  ss=mo,s1=0;  origin();  for (i=1;i<=r;i++) if (st[i]!=0) dfs2(0,st[i],st[i]);  fgm(f,f,m);  s=(1<<((n-1)*2)),s+=2;  i=hash(s),j=hash(0);  ans=f.w[i][j];  printf("%d\n",ans);}int main(){  freopen("input.txt","r",stdin);  freopen("output.txt","w",stdout);    init();  return 0;}

ural1519

#include <cstdio>#include <cstdlib>#include <cstring>const int mo=1000003,mt=150000;bool a[30][30];int v[mt],u,e,n,m,st[2][mt],r[2],next[3000000],id[3000000],w[3000000],ss,s1,ts[100],net[mt][50],prim[50];long long f[2][mt],ans;void change(int i,int nv,int ns){  if (!v[nv]) v[nv]=++r[u],st[u][r[u]]=ns,f[u][v[nv]]=0;  f[u][v[nv]]+=f[e][i];    }int hash(int s){  int h,r,i,ne;  h=s%mo;  for (;next[h]!=0;) {    h=next[h];    if (w[h]==s) return id[h];  }  ss++,next[h]=ss,id[ss]=++s1,w[ss]=s;  for (i=1,r=0;s;s>>=2,i++) {    ne=s&3;    if (2==ne) ts[++r]=i;    else if (1==ne) net[s1][i]=ts[r],net[s1][ts[r]]=i,r--;  }  return s1;}void swap(int yy,int s,int &ns) {    int na=(s>>yy)&3,ne=(s>>(yy-2))&3;    ns=(s&prim[yy>>1])&(prim[(yy>>1)-1]);    ns=ns | (ne<<yy) | (na<<(yy-2));}void replace(int lo,int &ns,int na){  lo=lo-1;  ns=(ns&prim[lo]) | (na<<(lo<<1));}void updata(int i,int x,int y){   int yy=(m-y)<<1,s=st[e][i],s1=hash(s),nv,ns;   if ((0==((s>>yy)&3))&&(0==((s>>(yy-2))&3))) {      if (!a[x][y+1]) {nv=hash(s),change(i,nv,s);return ;      }      if ((a[x+1][y+1])&&(a[x][y+2])) {        ns=(s | (1<<yy)) | (2<<(yy-2));nv=hash(ns);        change(i,nv,ns);      }   }   else if ((0==((s>>yy)&3))||(0==((s>>(yy-2))&3))) {      if (!a[x][y+1]) return ;      if (0==((s>>(yy-2))&3)) {        if (a[x][y+2]) swap(yy,s,ns),nv=hash(ns),change(i,nv,ns);            if (a[x+1][y+1]) nv=hash(s),change(i,nv,s);      }      else {        if (a[x+1][y+1]) swap(yy,s,ns),nv=hash(ns),change(i,nv,ns);        if (a[x][y+2]) nv=hash(s),change(i,nv,s);      }   }   else if (!((1==((s>>yy)&3))&&(2==((s>>(yy-2))&3)))) {      if (!a[x][y+1]) return ;      ns=(s&prim[yy>>1])&(prim[(yy>>1)-1]);      if (((1==((s>>yy)&3))&&(1==((s>>(yy-2))&3)))) {        replace(net[s1][(yy>>1)],ns,1);        nv=hash(ns);        change(i,nv,ns);      }      else if ((2==((s>>yy)&3))&&(2==((s>>(yy-2))&3))) {        replace(net[s1][(yy>>1)+1],ns,2);        nv=hash(ns);        change(i,nv,ns);      }      else nv=hash(ns),change(i,nv,ns);  }}void origin(){  int i,j;  prim[0]=((1<<31)-1)-3;  for (i=1;i<=14;i++) {    j=i,prim[i]=1;    for (j=i*2+3;j<=31;j++) prim[i]=(prim[i]<<1)+1;        prim[i]<<=2;        for (j=1;j<=i*2;j++) prim[i]=(prim[i]<<1)+1;  }}void init(){  int i,j,x,y,s,yy,la,lb;  char ch;  scanf("%d%d\n",&n,&m);  memset(a,0,sizeof(a));  for (i=1;i<=n;i++) {    for (j=1;j<=m;j++) {      scanf("%c",&ch);      if ('*'==ch) a[i][j]=0;else a[i][j]=1,la=i,lb=j;    }    scanf("\n");  }  origin();  ss=mo,s1=0;  st[e=0][r[e]=1]=0,f[e][1]=1;  x=1,y=0;  for (;(x!=la)||(y!=lb);e=u) {    memset(v,0,sizeof(v));    u=e^1,r[u]=0;    if (y==m) {      for (i=1;i<=r[e];i++) st[u][++r[u]]=st[e][i]>>2,f[u][r[u]]=f[e][i];      y=0,x++;    }    else {      for (i=1;i<=r[e];i++) updata(i,x,y);y++;    }//    for (i=1;i<=r[e];i++) printf("%d ",st[e][i]);printf("\n");  }  ans=0,u=e^1;  for (i=1;i<=r[u];i++) {    s=st[u][i],yy=(m-lb)<<1;    if ((((s>>yy)&3)==2)&&(((s>>yy+2)&3)==1)) ans+=f[u][i];  }  printf("%I64d\n",ans);}int main(){  freopen("ural1519.in","r",stdin);  freopen("ural1519.out","w",stdout);    init();   return 0; }

方便玩水管的程序,与我的程序配套,最高位为第一位

# include <cstdlib># include <cstdio># include <cmath># include <cstring>using namespace std;int main(){int tmp, m, d, g[20];int stop = 0;printf("len=?\n");scanf("%d", &m);m++;printf("询问吧,我的主人~.~\n"); while( stop < 1000 ){memset(g, 0, sizeof(g));scanf("%d", &d); stop++;printf("%d的四进制为: ", d) ;for (int i = 1;i <= m;i++, d/= 4)  g[++g[0]] = d%4;for (int i = 1;i*2 <= m; i++)  tmp = g[i], g[i] = g[m-i+1], g[m-i+1] = tmp;for (int i = 1; i <= m; i++)  printf("%d", g[i]);printf("\n");printf("括号序列:");for (int i = 1; i <= g[0]; i++)if (g[i] == 0) printf("*");else if (g[i] == 1) printf("(");else printf(")"); printf("\n"); }return 0;}


原创粉丝点击