您的位置:首页 > 其它

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

2012-03-10 14:54 148 查看
以前觉得插头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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: