插頭dp模板(簡單路徑+一條迴路+廣義路徑)

#include<cstdio>
#include<algorithm>
#include<cstring>
#define Ms(a,x) memset(a,x,sizeof(a))
/*
插頭dp模板
1.解決1條簡單路徑問題
2.本模板使用括號表示法,hash使用鏈表
4.輸入的爲地圖權值,輸出的爲一條簡單路徑可以得到的最大權值(有障礙,路可以不走)
5.記得當狀態表示的太大時code的類型要改爲longlong
*/
using namespace std;
typedef long long Int;
const int Hashsize=10007;
const int Maxstate=15000;
int n,m;
int Map[12][12];
Int ans;
inline void up(Int &x,Int y)
{
   if(y>x)x=y;
}
void input()
{
   scanf("%d%d",&n,&m);
   ans=0;
   for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
         scanf("%d",&Map[i][j]),up(ans,Map[i][j]);
}
inline int get(int code,int y)
{
   return code>>2*y&3;
}
inline int shift(int x,int y)
{
  return x<<2*y;
}
struct Hash
{
   int state[Maxstate],head[Hashsize],nxt[Maxstate];
   Int w[Maxstate];
   int tot;
   void init()
   {
      Ms(head,-1);
      tot=0;
   }
   void insert(int x,Int y)
   {
      int t=x%Hashsize;
      for(int i=head[t];~i;i=nxt[i])
         if(state[i]==x)
         {
            up(w[i],y);
            return;
         }
      nxt[tot]=head[t];
      head[t]=tot;
      w[tot]=y;
      state[tot++]=x;
   }
   void pt()//debug專用
   {
      printf("tot=%d\n",tot);
      for(int i=0;i<tot;i++)
      {
        for(int j=0,t=state[i];j<=m+1;j++,t>>=2)
           printf("%3d ",t&3);
        printf("w=%lld\n",w[i]);
      }puts("");
   }
}h[2];
void modify(int &code,int loc,int tar,int dir,int ned)
{
   int incode[13],i,t;
   for(i=0,t=code;i<=m;i++,t>>=2)
      incode[i]=t&3;
   int cnt=0;
   for(i=loc;;i+=dir)
      if(incode[i]==ned)
      {
         if(!cnt){code+=(tar-get(code,i))*shift(1,i);return;}
         cnt--;
      }
      else if(incode[i]==3-ned)cnt++;
}
void dp(int cs,int x,int y)
{
   for(int i=0;i<h[cs].tot;i++)
   {
      int code=h[cs].state[i];
      //printf("%d %d %d\n",code,x,y);
      int dep=get(code,m+1);
      Int w=h[cs].w[i]+Map[x][y];
      if(x&&!y)
      {
        code-=shift(dep,m+1);
        code<<=2;code+=shift(dep,m+1);
      }
      int left=get(code,y),up=get(code,y+1);
      if(!Map[x][y])
      {
         if(!left&&!up)h[cs^1].insert(code,w);
         continue;
      }
      if(left&&up)
      {
         code-=shift(left,y)+shift(up,y+1);
         if(left==3&&up==3)
         {
            h[cs^1].insert(code,w);
            continue;
         }
         if(left==3||up==3)
         {
            int di,ned;
            if(left==3)ned=up;
            else ned=left;
            di=ned==1?1:-1;
            modify(code,left==3?y+1:y,3,di,3-ned);//code,loc,tar,dir,ned
            h[cs^1].insert(code,w);
            continue;
         }
         if(left==up)
         {
            modify(code,left==1?y+1:y,left,left==1?1:-1,3-left);
            h[cs^1].insert(code,w);
            continue;
         }
         if(left==2&&up==1)
         {
            h[cs^1].insert(code,w);
            continue;
         }
         continue;
      }
      if(!left&&!up)
      {
         if(x<n-1&&y<m-1)
            h[cs^1].insert(code+shift(1,y)+shift(2,y+1),w);
         if(dep<2)
         {
            if(x<n-1)h[cs^1].insert(code+shift(3,y)+shift(1,m+1),w);
            if(y<m-1)h[cs^1].insert(code+shift(3,y+1)+shift(1,m+1),w);
         }
         h[cs^1].insert(code,w-Map[x][y]);
         continue;
      }
      if(left&&!up)
      {
        if(dep<2)
        {
           int code1=code;
           code1+=shift(1,m+1)-shift(left,y);
           if(left==1)modify(code1,y,3,1,2);
           else if(left==2)modify(code1,y,3,-1,1);
           h[cs^1].insert(code1,w);
        }
        if(x<n-1)h[cs^1].insert(code,w);
        if(y<m-1)h[cs^1].insert(code-shift(left,y)+shift(left,y+1),w);
        continue;
      }
      if(!left&&up)
      {
        if(dep<2)
        {
           int code1=code;
           code1+=shift(1,m+1)-shift(up,y+1);
           if(up==1)modify(code1,y+1,3,1,2);
           else if(up==2)modify(code1,y+1,3,-1,1);
           h[cs^1].insert(code1,w);
        }
        if(y<m-1)h[cs^1].insert(code,w);
        if(x<n-1)h[cs^1].insert(code-shift(up,y+1)+shift(up,y),w);
        continue;
      }
   }
}
void solve()
{
   int cs=0;
   //int all=0;
   h[0].init();
   h[0].insert(0,0);
   for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
      {
        h[cs^1].init();
        dp(cs,i,j);
        cs^=1;
        //debug專用
        //printf("轉移完%d %d\n",i,j);
        //h[cs].pt();
    //    all=max(all,h[cs].tot);
      }
   for(int i=0;i<h[cs].tot;i++)
      up(ans,h[cs].w[i]);
   printf("%lld\n",ans);
}
int main()
{
   int T;
   scanf("%d",&T);
   while(T--)
   {
      input();
      solve();
   }
   return 0;
}
/*
插頭dp模板
1.解決全圖爲一條迴路,有障礙
2.括號匹配:0:無插頭,1:左插頭,2:右插頭
3.極限數據12 12 無障礙:1076226888605605706
*/
#include<bits/stdc++.h>
using namespace std;
const int Hashsize=10007;
typedef long long Int;
int n,m,ex,ey;//ex,ey爲最後一個非障礙格
bool Map[12][12];
char s[12];
void input()
{
    for(int i=0;i<n;i++)
    {
        scanf("%s",s);//比如把這句註釋了,輸入12 12,應該得到1076226888605605706
        for(int j=0;j<m;j++)Map[i][j]=s[j]=='#'?1:0;
    }
    ex=n-1,ey=m-1;
}
struct Hash
{
    vector<int>state,nxt;
    vector<Int>w;
    int head[Hashsize];
    int tot;
    void init()
    {
        memset(head,-1,sizeof(head));
        tot=0;
        state.clear();
        nxt.clear();
        w.clear();
    }
    void insert(int x,Int y)
    {
        int t=x%Hashsize;
        for(int i=head[t];i!=-1;i=nxt[i])
        {
            if(state[i]==x)
            {
                w[i]+=y;
                return;
            }
        }
        nxt.push_back(head[t]);
        state.push_back(x);
        w.push_back(y);
        head[t]=tot++;
    }
}h[2];
inline int get(int code,int y)
{
    return code>>2*y&3;
}
inline int shift(int x,int y)
{
    return x<<2*y;
}
void modify(int &code,int loc,int pace)
{
    int ned=pace>0?2:1;
    int incode[13];
    for(int i=0,t=code;i<=m;i++,t>>=2)
        incode[i]=t&3;
    int cnt=0;
    for(int i=loc;;i+=pace)
    {
        if(incode[i]==ned)
        {
            if(!cnt){code-=pace*shift(1,i);return;}
            cnt--;
        }
        else if(incode[i])cnt++;
    }
}
void dp(int cs,int x,int y)//記得設置ex,ey
{
    if(Map[x][y])
    {
        for(int i=0;i<h[cs].tot;i++)
        {
            int code=h[cs].state[i];
            if(x&&!y)code<<=2;
            int left=get(code,y),up=get(code,y+1);
            if(!left&&!up)h[cs^1].insert(code,h[cs].w[i]);
        }
        return;
    }
    for(int i=0;i<h[cs].tot;i++)
    {
        int code=h[cs].state[i];
        Int w=h[cs].w[i];
        if(x&&!y)code<<=2;
        int left=get(code,y),up=get(code,y+1);
        if(left&&up)
        {
            code-=shift(left,y)+shift(up,y+1);
            if(left!=up)
            {
                if((x==ex&&y==ey)||left==2)
                    h[cs^1].insert(code,w);
                continue;
            }
            if(left==1)
            {
                modify(code,y+2,1);
                h[cs^1].insert(code,w);
                continue;
            }
            if(left==2)
            {
                modify(code,y-1,-1);
                h[cs^1].insert(code,w);
                continue;
            }
        }
        if(left&&!up)
        {
            if(x<n-1)h[cs^1].insert(code,w);
            if(y<m-1)h[cs^1].insert(code-shift(left,y)+shift(left,y+1),w);
            continue;
        }
        if(up&&!left)
        {
            if(y<m-1)h[cs^1].insert(code,w);
            if(x<n-1)h[cs^1].insert(code-shift(up,y+1)+shift(up,y),w);
        }
        if(!left&&!up&&x<n-1&&y<m-1)
            h[cs^1].insert(code+shift(1,y)+shift(2,y+1),w);
    }
}
void solve()
{
    int cs=0;
    h[0].init();
    h[0].insert(0,1);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            printf("i=%d j=%d\n",i,j);
            printf("tot=%d\n",h[cs].tot);
            h[cs^1].init();
            dp(cs,i,j);
            cs^=1;
        }
    }
    Int ans=0;
    for(int i=0;i<h[cs].tot;i++)
        ans+=h[cs].w[i];
    printf("%lld\n",ans);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        input();
        solve();
    }
}
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define Ms(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long Int;
const int Hashsize=10007,Maxstate=15000;
char Map[9][9];
char ch[]={'o','#'};
int pre[9][9][Maxstate];
int pe[9][9][Maxstate];
int n,m;
/*
原題 uva10572 廣義路徑
題意:棋盤只能塗黑白,黑白各自聯通,不能有2*2的方塊塗有相同的顏色,要求輸出方案數和其中一種方案
*/
inline int shift(int x,int y)
{
    return x<<y;
}
inline int get(int x,int y)
{
   return x>>y&1;
}
struct Hash
{
   int head[Hashsize];
   int nxt[Maxstate],state[Maxstate],col[Maxstate];
   Int w[Maxstate];
   int tot;
   void init()
   {
      tot=0;
      Ms(head,-1);
   }
   void insert(int st,int cl,Int ww,int x,int y,int pst,int cs)
   {
      int t=((st<<5)+cl)%Hashsize;
      for(int i=head[t];~i;i=nxt[i])
        if(state[i]==st&&col[i]==cl)
        {
           w[i]+=ww;
           pre[x][y][i]=pst;
           pe[x][y][i]=cs;
           return;
        }
      nxt[tot]=head[t];
      head[t]=tot;
      state[tot]=st,col[tot]=cl,w[tot]=ww;
      pe[x][y][tot]=cs;
      pre[x][y][tot++]=pst;
   }
   //for debug
   void pt()
   {
       printf("tot=%d\n",tot);
       for(int i=0;i<tot;i++)
       {
           printf("state= ");
           for(int j=0,k=state[i];j<m;j++,k>>=3)
              printf("%3d",k&7);
            puts("");
           printf("col= ");
           for(int j=0,k=col[i];j<m+3;j++,k>>=1)
              printf("%3d",k&1);
            puts("");
           printf("w=%lld\n",w[i]);
           puts("");
       }
   }
}h[2];
int code[10];
void decode(int cd)
{
   for(int i=0;i<m;i++,cd>>=3)
     code[i]=cd&7;
}
int encode()
{
   int ref[10],cnt=0;
   Ms(ref,-1);
   for(int i=0;i<m;i++)
   {
      if(ref[code[i]]<0)
         ref[code[i]]=cnt++;
      code[i]=ref[code[i]];
   }
   int ret=0;
   for(int i=m-1;i>=0;i--)
      ret=(ret<<3)+code[i];
   return ret;
}
bool check(int y,int st)
{
   for(int i=st;i<m;i++)
      if(i!=y&&code[i]==code[y])
          return true;
   return false;
}
void modify(int loc,int x)
{
   int t=code[loc];
   for(int i=0;i<m;i++)
      if(code[i]==t)
         code[i]=x;
}
void dp(int cs,int x,int y,int cl)
{
   if(Map[x][y]!='.'&&Map[x][y]!=ch[cl])return;
   //col的第0-m位表示格子的顏色,m+1-m+2表示是否只能使用一種顏色10只能用白色,11只能用黑色
   for(int i=0;i<h[cs].tot;i++)
   {
      int col=h[cs].col[i],st=h[cs].state[i];
      int last=col>>(m+1);
      col-=last<<(m+1);
      if(x&&!y)
      {
         col=col&shift(1,m)-1;
         col<<=1;
      }
      //ul,ur,dl分別表示左上、右上、左下的格子的顏色
      int ul=0,ur=0,dl=0;
      if(x){ul=get(col,y);ur=get(col,y+1);}
      if(y)dl=get(col,y-1);
      //這四個格子顏色不能全部相同
      if(x&&y&&dl==ul&&ul==ur&&ul==cl)
         continue;
      //如果後面的格子只能使用一種顏色但與當前使用的不同,則不合法
      if(last&&(last&1)!=cl)continue;
      col+=(cl-ul)*shift(1,y);
      //解碼
      decode(st);
      //考慮一些聯通分量消失的格子,如果他們所處的聯通分量消失了,則後面只能塗一種顏色
      bool flag=false;
      if(x&&ur!=cl&&!check(y,x==n-1?y+1:0))
      {
         if(last)continue;
         flag=true;
      }
      if(x==n-1&&y&&!last&&dl!=cl&&!check(y-1,y+1))
      {
         if(last)continue;
         if(flag&&code[y-1]!=code[y])continue;
         flag=true;
      }
      if(flag)last=2+cl;
      col+=last<<(m+1);
      //重新編碼+最小表示
      if(y&&cl==dl)modify(y-1,9);
      if(x&&ur==cl)modify(y,9);
      code[y]=9;
      h[cs^1].insert(encode(),col,h[cs].w[i],x,y,i,cl);
   }
}
vector<int>bef;
void solve()
{
   int cs=0;
   h[cs].init();
   h[cs].insert(0,0,1,0,0,0,0);

   for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
      {
         h[cs^1].init();
         for(int k=0;k<2;k++)
            dp(cs,i,j,k);
         cs^=1;
         //printf("轉移完%d %d\n",i,j);h[cs].pt();
      }
   Int ans=0;
   int last=-1;
   bef.clear();
   for(int i=0;i<h[cs].tot;i++)
   {
      if(h[cs].w[i])
         ans+=h[cs].w[i],last=i,bef.push_back(i);
   }
   if(!ans)puts("0\n");
   else
   {//for debug
     /*for(int k=0;k<bef.size();k++)
     {
       int st=bef[k];
       for(int i=n-1;i>=0;i--)
        for(int j=m-1;j>=0;st=pre[i][j][st],j--)
           Map[i][j]=pe[i][j][st]?'#':'o';
     for(int i=0;i<n;i++)
        printf("%s\n",Map[i]);
        puts("");
     }*/
     printf("%lld\n",ans);
     for(int i=n-1;i>=0;i--)
        for(int j=m-1;j>=0;last=pre[i][j][last],j--)
           Map[i][j]=pe[i][j][last]?'#':'o';
     for(int i=0;i<n;i++)
        printf("%s\n",Map[i]);
     puts("");
   }
}
void input()
{
   scanf("%d%d",&n,&m);
   for(int i=0;i<n;i++)
      scanf("%s",Map[i]);
}
int main()
{
   int T;
   scanf("%d",&T);
   while(T--)
   {
      input();
      solve();
   }
   return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章