hdu 4796 Winter's Coming 插头DP

来源:互联网 发布:javascript是谁发明的 编辑:程序博客网 时间:2024/04/30 04:35

目前OJ上跑的最快 187ms
要求建造城墙把W分在左边,L分在右边,并且上下联通

做法是从地图第一行上面连一个插头下来。DP的最终状态是最后一行连一个插头到下面。
至于W分在左边,L分在右边,做法是:
保证任意一个W左边的下插头为偶数个,L的下插头为奇数个。

具体看代码

#include<stdio.h>#include<string.h>#include<ctype.h>#include<math.h>#include<string>#include<cstdlib>#include<set>#include<map>#include<vector>#include<queue>#include<algorithm>using namespace std;void fre(){freopen("t.txt","r",stdin);}template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }#define ls o<<1#define rs o<<1|1#define MS(x,y) memset(x,y,sizeof(x))#define MC(x, y) memcpy(x, y, sizeof(x))typedef long long LL;typedef unsigned int UI;const int Z = 1e9+7,inf = 1e9;template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a+=b; if(a >= Z) a%=Z; }int cas;const int MAXD=15,HASH=30007;const int STATE=1000010;int maze[25][MAXD];int code[MAXD],ch[MAXD];int n,m,ex,ey,ans;struct HASHMAP{    int head[HASH],next[STATE],size;    LL state[STATE];    LL f[STATE];    void init()    {        size=0;        memset(head,-1,sizeof(head));    }    void push(LL st,LL ans)    {        int i;        int h=st%HASH;        for(i=head[h];i!=-1;i=next[i])            if(state[i]==st)            {                gmin(f[i],ans);                return;            }        state[size]=st;        f[size]=ans;        next[size]=head[h];        head[h]=size++;    }}hm[2];void decode(int *code,int m,LL  st)//解码{    for(int i=m;i>=0;i--)    {        code[i]=st&7;        st>>=3;    }}LL encode(int *code,int m)//状态压缩{    int cnt=1;    MS(ch,-1);    ch[0]=0;    LL st=0;    for(int i=0;i<=m;i++)    {        if(ch[code[i]]==-1)ch[code[i]]=cnt++;        st<<=3;        st|=ch[code[i]];    }    return st;}void shift(int *code,int m)//换行{    for(int i=m;i>0;i--)code[i]=code[i-1];    code[0]=0;}void dpblank(int i,int j,int cur){    int left,up;    for(int k=0;k<hm[cur].size;k++)    {        decode(code,m,hm[cur].state[k]);        left=code[j-1];        up=code[j];        if(left&&up)        {            if(left != up)            {                code[j-1]=code[j]=0;                for(int t=0;t<=m;t++)                    if(code[t]==up) code[t]=left;                if(j==m)shift(code,m);                hm[cur^1].push(encode(code,m),hm[cur].f[k]+maze[i][j]);            }        }        else if(left || up)        {            int t;            if(left) t=left;            else t=up;            if(maze[i][j+1] >= 0)            {                code[j-1]=0;                code[j]=t;                hm[cur^1].push(encode(code,m),hm[cur].f[k] + maze[i][j]);            }            if(maze[i+1][j] >= 0)            {                code[j-1]=t;                code[j]=0;                if(j==m)shift(code,m);                hm[cur^1].push(encode(code,m),hm[cur].f[k] + maze[i][j]);            }        }        else        {            if(j == m) shift(code,m);            hm[cur^1].push(encode(code,m),hm[cur].f[k]);            if(maze[i][j+1] >= 0&&maze[i+1][j] >= 0)            {                code[j-1]=code[j]=13;                hm[cur^1].push(encode(code,m),hm[cur].f[k] + maze[i][j]);            }        }    }}void dpblock(int i,int j,int cur){    int k;    for(k=0;k<hm[cur].size;k++)    {        decode(code,m,hm[cur].state[k]);        if(maze[i][j] == -3)//W的判断        {            int c = 0;            for(int p = 0; p < j-1; ++p)                if(code[p]) c++;            if(c&1) continue;        }        if(maze[i][j] == -2)//L的判断        {            int c = 0;            for(int p = 0; p < j-1; ++p)                if(code[p]) c++;            if(c%2 == 0) continue;        }        code[j-1]=code[j]=0;        if(j==m) shift(code,m);        hm[cur^1].push(encode(code,m),hm[cur].f[k]);    }}void solve(){    int cur=0;    ans= inf;    hm[cur].init();    MS(code,0);    for(int i = 1; i <= m; ++i)//状态转移起点,从上面加一个插头下来    {        code[i-1] = 0; code[i] = 13;        hm[cur].push(encode(code,m),0);    }    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        {            hm[cur^1].init();            if(maze[i][j] >= 0) dpblank(i,j,cur);            else  dpblock(i,j,cur);            cur^=1;        }    for(int i=0;i<hm[cur].size;i++)//统计答案,要求只有一个通往地图下面的插头    {        decode(code,m,hm[cur].state[i]);        int c = 0;for(int i = 0; i <= m; ++i) if(code[i]) c++;        if(c != 1) continue;        gmin(ans,hm[cur].f[i]);    }    if(ans != inf) printf("%d\n",ans);    else puts("-1");}char str[MAXD];int main(){    while(scanf("%d%d",&n,&m)!=EOF)    {        MS(maze,-1); ex=0;        for(int i=1;i<=n;i++)        {            scanf("%s",str+1);            for(int j=1;j<=m;j++)            {                if(str[j] == '#') maze[i][j] = -1;                else if(str[j] == 'L') maze[i][j] = -2;                else if(str[j] == 'W') maze[i][j] = -3;                else maze[i][j] = str[j] - '0';            }        }        for(int i = 1; i <= m; ++i) maze[n+1][i] = 0;        solve();    }    return 0;}
1 0
原创粉丝点击