fzu 1977 Pandora adventure(插头DP一条回路 格子的占用或不占用)

本文介绍了一道算法题目“PandoraAdventure”,任务是在一张包含障碍物的地图中找到能够收集所有指定资源并返回起点的所有可能路径的数量。文章提供了详细的题目背景、输入输出示例及代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Problem 1977 Pandora adventure

Accept: 244    Submit: 813
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

The pollution of the earth is so serious that people can not survive any more. Fortunately, people have found a new planet that maybe has life, and we call it "Pandora Planet".

Leonardo Da Vinci is the only astronaut on the earth. He will be sent to the Pandora Planet to gather some plant specimens and go back. The plant specimen is important to the people to decide whether the planet is fit to live or not.

Assuming that Da Vinci can only move in an N×M grid. The positions of the plant specimens he wants to collect are all marked by the satellite. His task is to find a path to collect all the plant specimens and return to the spaceship. There are some savage beasts in the planet. Da Vinci can not investigate the grid with the savage beast. These grids are also marked by the satellite. In order to save time Da Vinci could only visit each grid exactly once and also return to the start grid, that is, you can not visit a grid twice except the start grid. You should note that you can choose any grid as the start grid.

Now he wants to know the number of different paths he can collect all the plant specimens. We only care about the path and ignore where the start grid is, so the two paths in Figure 1 are considered as the same.

Figure 1

 Input

The first line of the input contains an integer T (T≤100), indicating the number of cases. Each case begins with a line containing two integers N and M (1≤N, M≤12), the size of the planet is N×M. Each of the following N lines contains M characters Gij(1≤i≤N, 1≤j≤M), Gij denotes the status of the grid in row i and column j, where 'X' denotes the grid with savage beast, '*' denotes the safe grid that you can decide to go or not, 'O' denotes the plant specimen you should collect. We guarantee that there are at least three plant specimens in the map.

 Output

For each test case, print a line containing the test case number (beginning with 1) and the number of different paths he can collect all the plant specimens. You can make sure that the answer will fit in a 64-bit signed integer.

 Sample Input

22 2OOO*4 4***OXO****O*XX**

 Sample Output

Case 1: 1Case 2: 7

 Source

The 35th ACM/ICPC Asia Regional Fuzhou Site —— Online Contest

题目: http://acm.fzu.edu.cn/problem.php?pid=1977

题意:给你一个地图,地图上有些资源,还有一些不可走的格子,找到一条回路,使得所有资源被收集,每次只能通过格子一次。。。。

分析:看似比较复杂,仔细想想还是简单的插头DP一条回路,对于不必须去的格子,多加一个空插头是也可以直接下传状态就行,还有,判断合并的条件是当前的格子在所有资源的后面。。。也就是已经收集了所有资源才可以合并,并且状态不下传。。

貌似有点慢240ms++

代码:

#include<cstdio>
#include<cstring>s
#include<iostream>
using namespace std;
const int mm=100007;
typedef long long LL;
struct hashMap
{
    int h[mm],s[mm],p[mm],t;
    LL v[mm];
    void push(int w,LL val)
    {
        int i,id=w%mm;
        for(i=h[id];i>=0;i=p[i])
        if(s[i]==w)
        {
            v[i]+=val;
            return;
        }
        v[t]=val,s[t]=w,p[t]=h[id],h[id]=t++;
    }
    void clear()
    {
        t=0,memset(h,-1,sizeof(h));
    }
}f[2];
int g[22][22];
int i,j,k,g1,g2,n,m,en,em,t,cs=0;
LL ans;
char c;
bool ok(int s)
{
    if(s==1)return g[i+1][j];
    if(s==2)return g[i][j+1];
    return g[i+1][j]&&g[i][j+1];
}
int Link(int s,int flag)
{
    int n=1,w,x=3<<(j<<1),a=(2-flag)<<(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,LL val)
{
    int e,w=j<<1,x=(s>>w)&15;
    if(x==9)
    {
        if((i>en||(i==en&&j>=em))&&!(s^(x<<w)))ans+=val;
    }
    else if(!x)
    {
        if(ok(3))f[g2].push(s^(9<<w),val);
        if(g[i][j]==1)f[g2].push(s,val);
    }
    else if(!(x&3)||!(x&12))
    {
        if(x&3)e=0,x|=x<<2;
        else e=1,x|=x>>2;
        if(ok(1+e))f[g2].push(s,val);
        if(ok(1+!e))f[g2].push(s^(x<<w),val);
    }
    else if(x==6)f[g2].push(s^(x<<w),val);
    else f[g2].push(Link(s^(x<<w),x==5),val);
}
void end()
{
    for(en=n-1;en>=0;--en)
        for(em=m-1;em>=0;--em)
            if(g[en][em]==2)return;
}
void PlugDP()
{
    end();
    f[0].clear();
    f[0].push(0,1);
    for(ans=g2=i=0;i<n;++i)
    {
        for(k=0;k<f[g2].t;++k)f[g2].s[k]<<=2;
        for(j=0;j<m;++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 main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(g,0,sizeof(g));
        scanf("%d%d",&n,&m);
        for(i=0;i<n;++i)
            for(j=0;j<m;++j)
                scanf(" %c",&c),g[i][j]=(c=='X')?0:((c=='*')?1:2);
        PlugDP();
        printf("Case %d: %I64d\n",++cs,ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值