usaco 5.4 Betsy's Tour(插头DP一条回路)

Betsy's Tour
Don Piele

A square township has been divided up into N2 square plots (1 <= N <= 7). The Farm is located in the upper left plot and the Market is located in the lower left plot. Betsy takes her tour of the township going from Farm to Market by walking through every plot exactly once. Shown below is one possible tour for Betsy when N=3.

----------------
|    |    |    |
| F**********  |
|    |    | *  |
------------*---
|    |    | *  |
|  *****  | *  |
|  * | *  | *  |
---*---*----*---
|  * | *  | *  |
|  M | ******  |
|    |    |    |
----------------
Write a program that will count how many unique tours Betsy can take in going from Farm to Market for any value of N.

PROGRAM NAME: betsy

INPUT FORMAT

Line 1: A single integer N (1 <= N <= 7)

SAMPLE INPUT (file betsy.in)

3

OUTPUT FORMAT

A single line with a single integer, the number of unique tours.

SAMPLE OUTPUT (file betsy.out)

2

题意:求一条路径从左上角到左下角,遍历所有格子,问这样的路径有几条

分析:因为之前做过插头DP所有一眼就知道是插头DP一条回路的问题,不过这题的数据范围应该是让用搜索写的,我借此机会复习了下,插头DP,秒杀之

这题需要转换一下,一开始有一个右插头或左插头指向第一个,最后留个插头指向最后一行下面一行的第一个,剩下的就是一条回路问题了,直接套用模板,搞定之

PS:终于又可以手敲插头DP了,尽量在比赛前熟悉所有的算法和题型

代码:

/*
ID: 15114582
PROG: betsy
LANG: C++
*/
#include<cstdio>
#include<cstring>
using namespace std;
const int mm=10007;
struct hashTable
{
    int h[mm],s[mm],p[mm],v[mm],t;
    void push(int mask,int val)
    {
        int i,id=mask%mm;
        for(i=h[id];i>=0;i=p[i])
        if(s[i]==mask)
        {
            v[i]+=val;
            return;
        }
        v[t]=val,s[t]=mask,p[t]=h[id],h[id]=t++;
    }
    void clear()
    {
        t=0,memset(h,-1,sizeof(h));
    }
}f[2];
int i,j,k,n,g1,g2;
bool g[11][11];
bool ok(int s)
{
    if(s==1)return g[i+1][j];
    if(s==2)return g[i][j+1];
    if(s==3)return g[i+1][j]&&g[i][j+1];
}
int Link(int s,bool flag)
{
    int n=1,w,x=3<<(j<<1),a=(flag?1:2)<<(j<<1);
    while(n)
    {
        if(flag)a<<=2,x<<=2;
        else a>>=2,x>>=2;
        w=s&x;
        if(w)n+=(w==a)?1:-1;
    }
    return s^x;
}
void Work(int s,int val)
{
    int e,w=j<<1,ss=(s>>w)&15;
    if(ss==9)return;
    if(!ss)
    {
        if(ok(3))f[g2].push(s|(9<<w),val);
    }
    else if(!(ss&3)||!(ss&12))
    {
        if(ss&3)e=0,ss|=ss<<2;
        else e=1,ss|=ss>>2;
        if(ok(1+e))f[g2].push(s,val);
        if(ok(1+!e))f[g2].push(s^(ss<<w),val);
    }
    else if(ss==6)f[g2].push(s^(ss<<w),val);
    else f[g2].push(Link(s^(ss<<w),ss==5),val);
}
int PlugDP()
{
    f[0].clear();
    f[0].push(1,1);
    for(g2=i=0;i<n;++i)
    {
        for(k=0;k<f[g2].t;++k)f[g2].s[k]<<=2;
        for(j=0;j<n;++j)
            if(g[i][j])for(g1=g2,g2=!g2,f[g2].clear(),k=0;k<f[g1].t;++k)
                Work(f[g1].s[k],f[g1].v[k]);
    }
    int ret=0;
    for(k=0;k<f[g2].t;++k)
        if(f[g2].s[k]==1)ret+=f[g2].v[k];
    return ret;
}
int main()
{
    freopen("betsy.in","r",stdin);
    freopen("betsy.out","w",stdout);
    while(~scanf("%d",&n))
    {
        memset(g,0,sizeof(g));
        for(i=0;i<n;++i)
            for(j=0;j<n;++j)g[i][j]=1;
        g[n][0]=1;
        printf("%d\n",PlugDP());
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值