Vijos P1110 小胖邮递员(HNOI2004)题解

288行代码,恩……
网上抄的代码,自己翻译,排版了一下,给大家学习。
主要方法是状态压缩dp,然后就是高精度,最后加一点特判。
主要,n或m为1时路径只有1条,而不是0条,
虽然是最短,但没说不可以重复走一个点。
但n=3,m=3这种情况不知道怎么搞,还好好像没这个点……
恩,这是他的题解:http://timeplayer.blog.163.com/blog/static/2037182542014839225594/

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int BIT = 177147+10;
int n,m;
int scan()
{
    char cc = ' ';
    int re = 0,fh = 1;
    while(cc == ' ' || cc == '\r' || cc == '\n')
        cc = getchar();
    if(cc=='+')
    {
        cc=getchar();
        fh=1;
    }
    if(cc=='-')
    {
        cc=getchar();
        fh=-1;
    }
    while('0'<=cc&&cc<='9')
    {
        re = re * 10 + cc - '0';
        cc = getchar();
    }
    return re * fh;
}

struct state{
    int i,d;
    state(){}
    state(int ii,int dd):i(ii),d(dd)
    {
    }
};

queue<state>dui;

const int LEN = 10+1;
const int L = 10000;

struct Big{
    int d[LEN],len;
    Big()
    {
        memset(d,0,sizeof(d));
        len=1;
    }

    Big operator = (int a)
    {
        if(!a)
        {
            *this = Big();
            return *this;
        }
        for(len = 0; a != 0 ; a /= L) 
            d[++len] = a % L;
    }

    void print()
    {
        printf("%d",d[len]);
        for(int i=len-1;i;i--)
            printf("%04d",d[i]);
    }
};
typedef Big BIG;

Big operator + (Big &A,Big &B)
{
    Big C;
    C.len = max(A.len,B.len) + 1;
    for(int i = 1; i <= C.len; ++ i)
    {
        C.d[i] += A.d[i] + B.d[i];
        if(C.d[i] >= L)
        {
            C.d[i+1] = C.d[i] / L;
            C.d[i] %= L;
        }
    }
    while(C.len > 1 && C.d[C.len] == 0)
        C.len--;
    return C;
}

BIG ans,f[2][BIT];
short v[2][BIT];

int pos(int x,int y)
{
    return (y - 1) * m + x - 1;
}

void list(int x,short a[])
{
    for(int i=1;i<=m+1;i++) 
        a[i] = 0;
    for(int i = 1; x != 0; ++ i,x = x / 3)
        a[i] = x % 3;
}

int zip(short a[],int x,int val1,int val2){
    int re=0;
    for(int i = m + 1; i != 0 ; -- i)
        if(i == x) 
            re = re * 3 + val1;
        else 
            if(i == x + 1)
                re = re * 3 + val2;
            else 
                re = re * 3 + a[i];
    return re;
}

short lin[12];

void pipei(int x,short a[],short type)
{
    int i,j,p1 = 0,p2 = 0;
    if(type==1)
    {
        for(j=0,i=x+2;i<=m+1;i++)
        {
            if(a[i]==2)
                j++;
            if(a[i]==1)
                j--;
            if(j > 0 && !p1)
            {
                p1=i;
                j--;
            }
            if(j > 0 && p1)
            {
                p2=i;
                break;
            }
        }
    }
    else
    {
        for(j=0,i=x-1;i;i--)
        {
            if(a[i]==1)
                j++;
            if(a[i]==2)
                j--;
            if(j > 0 && !p2)
            {
                p2=i;
                j--;
            }
            if(j > 0 && p2)
            {   
                p1=i;
                break;
            }
        }
    }
    a[p1] = 1;
    a[p2] = 2;
}

void update(int i,int zt,BIG &val,short upans = 0)
{
    i++;
    int i2 = i % 2;
    if(!upans)
    {
        if(v[i2][zt] != i)
        {
            f[i2][zt] = 0;
            v[i2][zt] = i;
            dui.push(state(i,zt));
            }
        f[i2][zt] = f[i2][zt]+val;
    }
    else 
        ans = ans + val;
}

short map[21][21];

bool lerror(short a[])
{
    int i,j;
    for(i=1,j=0;i<=m+1;i++)
    {
        if(a[i]==1) 
            j++;
        if(a[i]==2) 
            j--;
        if(j<0)
            return 1;
    }
    return j != 0;
}

int main(){
    int i,j,end;
    m=scan();
    n=scan();
    end = pos(m,n);
    dui.push(state(0,0));
    f[0][0] = 1;
    v[0][0] = 1;
    for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)
            map[i][j]=1;
    while(!dui.empty())
    {
        state now = dui.front();
        dui.pop();
        int x,y,tmp;
        i = now.i;
        BIG & last = f[i%2][now.d];
        if(i % m == 0) 
            now.d *= 3;
        x = i % m + 1;
        y = i / m + 1;
        list(now.d,lin);
        if(lin[x] == 1 && lin[x+1] == 2)
        {
            if(i == end) 
                update(i,0,last,1);
        }else 
            if(lin[x] == 2 && lin[x+1] == 1)
            {
                tmp = zip(lin,x,0,0);
                update(i,tmp,last);
            }
            else 
                if(lin[x] == 0 && lin[x+1] == 0)
                {
                    if(map[x][y+1] && map[x+1][y])
                    {
                        tmp = zip(lin,x,1,2);
                        update(i,tmp,last);
                    }
                }
                else 
                    if(lin[x] == 0)
                    {
                        if(map[x+1][y])
                        {
                            tmp = zip(lin,x,0,lin[x+1]);
                            update(i,tmp,last);
                        }
                        if(map[x][y+1])
                        {
                            tmp = zip(lin,x,lin[x+1],0);
                            update(i,tmp,last);
                        }
                    }
                    else 
                        if(lin[x+1] == 0)
                        {
                            if(map[x+1][y])
                            {
                                tmp = zip(lin,x,0,lin[x]);
                                update(i,tmp,last);
                            }
                            if(map[x][y+1])
                            {
                                tmp = zip(lin,x,lin[x],0);
                                update(i,tmp,last);
                            }
                        }
                        else 
                            if(lin[x] == lin[x+1])
                            {
                                pipei(x,lin,lin[x]);
                                tmp = zip(lin,x,0,0);
                                update(i,tmp,last);
                            }
    }
    ans = ans + ans;
    if(ans.len == 1 && ans.d[1] == 0) 
        ans = 1;
    ans.print();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值