• HDU 4026 Unlock the Cell Phone 状压dp(类似TSP)


    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=4026

    Unlock the Cell Phone

    Time Limit: 6000/3000 MS (Java/Others)
    Memory Limit: 65768/65768 K (Java/Others)
    #### 问题描述 > Modern high-tech cell phones use unlock patterns to unlock the system. The pattern is usually a 3*3 dot array. By moving your finger over there dots, you can generate your personal unlock pattern. More specifically, press your finger over any starting dot, then slide all the way to the next dot, touch it, and so on. Jumping is not allowed. For example, starting from dot 1, you can slide to touch dot 2, dot 4 and dot 5, but sliding directly to dot 3, dot 7 or dot 9 are not allowed. Note that sliding from 1 to 6 and 8 is also allowed because they are not considered as jumping over any dot. However, you can jump a dot if it has been touched before. For example, staring with 1-5-9-6, you can slide directly to dot 4. > Here is a very particular cell phone. It has a dot array of size n*m. Some of the dots are ordinary ones: you can touch, and slide over them when touched before; some are forbidden ones: you cannot touch or slide over them; some are inactive ones: you cannot touch them, but can slide over them. Each dot can only be touched once. You are required to calculate how many different unlock patterns passing through all the ordinary dots.

    输入

    The input contains several test cases. Each test case begins with a line containing two integers n and m (1 <= n, m <= 5), indicating the row and column number of the lock keypad. The following n lines each contains m integers kij indicating the properties of each key, kij=0 stands for an ordinary key, kih=1 stands for a forbidden key; and kij=2 stands for an inactive key. The number of ordinary keys is greater than zero and no more than 16.

    输出

    For each test, output an integer indicating the number of different lock patterns.

    样例输入

    2 2
    0 0
    0 0
    3 3
    0 0 0
    0 2 1
    0 0 0

    样例输出

    24
    2140

    题意

    给你一个手势解锁的n*m的键盘,0表示可以正常使用的,1表示不能碰触并且不能越过的,2表示不能碰触但是可以越过的。 问要把所有正常的都激活一遍的总的方案数有多少种。

    题解

    处理下什么情况是非法的,然后把可激活的单独拿出来激活下。

    代码

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<functional>
    using namespace std;
    #define X first
    #define Y second
    #define mkp make_pair
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define mid (l+(r-l)/2)
    #define sz() size()
    #define pb(v) push_back(v)
    #define all(o) (o).begin(),(o).end()
    #define clr(a,v) memset(a,v,sizeof(a))
    #define bug(a) cout<<#a<<" = "<<a<<endl
    #define rep(i,a,b) for(int i=a;i<(b);i++)
    #define scf scanf
    #define prf printf
    
    typedef long long LL;
    typedef vector<int> VI;
    typedef pair<int,int> PII;
    typedef vector<pair<int,int> > VPII;
    
    const int INF=0x3f3f3f3f;
    const LL INFL=10000000000000000LL;
    const double eps=1e-9;
    
    const double PI = acos(-1.0);
    
    //start----------------------------------------------------------------------
    
    const int maxm=17;
    
    int arr[11][11];
    int mp[33][33];
    int mmp[33];
    int n,m;
    
    VI G[33][33];
    LL dp[1<<maxm][maxm];
    
    ///判断中间有没有经过还没访问过的点或者中间有没有静止越过的点
    bool ok(int sta,int s1,int s2){
        if(mp[s1][s2]==1) return false;
        rep(i,0,G[s1][s2].sz()){
            int x=G[s1][s2][i];
            int id=mmp[x];
            if(!(sta&(1<<id))) return false;
        }
        return true;
    }
    
    void init(){
        clr(mp,0);
        clr(mmp,-1);
        rep(i,0,33) rep(j,0,33) G[i][j].clear();
    }
    
    int main() {
        while(scf("%d%d",&n,&m)==2&&n){
            init();
    
            ///把等于0的点单独挖出来状压
            VI vec;
            rep(i,0,n) rep(j,0,m){
                scf("%d",&arr[i][j]);
                if(arr[i][j]==0){
                    vec.pb(i*m+j);
                }
            }
    
            rep(i,0,vec.sz()){
                mmp[vec[i]]=i;
            }
    
            ///处理线段中间的点
            rep(i,0,vec.sz()){
                rep(j,0,vec.sz()){
                    if(i==j) continue;
                    int xi=vec[i]/m,yi=vec[i]%m;
                    int xj=vec[j]/m,yj=vec[j]%m;
    
                    for(int x=min(xi,xj);x<=max(xi,xj);x++){
                        for(int y=min(yi,yj);y<=max(yi,yj);y++){
                            if(x==xi&&y==yi||x==xj&&y==yj) continue;
                            if((yi-y)*(xj-x)!=(yj-y)*(xi-x)) continue;
    
                            if(arr[x][y]==1){
                                mp[vec[i]][vec[j]]=1;
                            }
                            if(mp[vec[i]][vec[j]]==1) continue;
    
                            if(arr[x][y]==0){
                                G[vec[i]][vec[j]].pb(x*m+y);
                            }
                        }
                    }
                }
            }
    
            ///状压
            int tot=vec.sz();
    
            clr(dp,0);
            rep(i,0,tot){
                dp[1<<i][i]=1;
            }
    
            rep(i,0,(1<<tot)){
                rep(j,0,tot){
                    if(!(i&(1<<j))) continue;
                    rep(k,0,tot){
                        if(k==j||(i&(1<<k))==0) continue;
    
                        if(ok(i,vec[k],vec[j])){
                            dp[i][j]+=dp[i^(1<<j)][k];
                        }
                    }
                }
            }
    
            LL ans=0;
            rep(i,0,tot){
                ans+=dp[(1<<tot)-1][i];
            }
    
            prf("%lld
    ",ans);
    
        }
        return 0;
    }
    
    //end-----------------------------------------------------------------------
  • 相关阅读:
    C#制作自定义安装程序
    (转)Linq DataTable的修改和查询
    (转)将rdlc报表作为资源嵌套使用
    C# 中的委托和事件(2)
    C# 中的委托和事件(1)
    C# 自定义控件入门
    Spring中自动装配(转)
    从程序员到CTO的Java技术路线图 (转自安卓巴士)
    spring四种依赖注入方式
    MyEclipse提示键配置、提示快捷键、提示背景色、关键字颜色、代码显示、编...
  • 原文地址:https://www.cnblogs.com/fenice/p/6009388.html
Copyright © 2020-2023  润新知