zoukankan      html  css  js  c++  java
  • SCOI 2009 围豆豆(状压DP)

    SCOI 2009 围豆豆

    题目描述

    是不是平时在手机里玩吃豆豆游戏玩腻了呢?最近MOKIA手机上推出了一种新的围豆豆游戏,大家一起来试一试吧。

    游戏的规则非常简单,在一个N×M的矩阵方格内分布着D颗豆子,每颗豆有不同的分值Vi。游戏者可以选择任意一个方格作为起始格,每次移动可以随意的走到相邻的四个格子,直到最终又回到起始格。最终游戏者的得分为所有被路径围住的豆豆的分值总和减去游戏者移动的步数。矩阵中某些格子内设有障碍物,任何时刻游戏者不能进入包含障碍物或豆子的格子。游戏者可能的最低得分为0,即什么都不做。

    注意路径包围的概念,即某一颗豆在路径所形成的多边形(可能是含自交的复杂多边形)的内部。

    输入格式

    第一行两个整数N和M,为矩阵的边长。

    第二行一个整数D,为豆子的总个数。

    第三行包含D个整数V1到VD,分别为每颗豆子的分值。

    接着N行有一个N×M的字符矩阵来描述游戏矩阵状态,0表示空格,#表示障碍物。而数字1到9分别表示对应编号的豆子。

    输出格式

    仅包含一个整数,为最高可能获得的分值

    Sample

    Input

    3 8
    3
    30 -100 30
    00000000
    010203#0
    00000000
    

    Output

    38
    

    Solution

    令人头大的一道题
    定义数组:(f[i][j][k])表示当前所在点为(i,j)走过了(k)
    k就是状压中的“状态”
    怎么理解k呢
    每一位i表示第i颗豆子有没有被围上
    0表示没有,1表示围上了
    假设有3颗豆子
    000都没有
    001一号围上了
    011一二号围上了
    100三号围上了
    以此类推

    然后就是判断有没有被围上的方法
    这个东西属实不知道
    是个叫做射线定理的东西
    我们从豆豆开始向右引一条射线(其实向哪一个方向都可以),如果射线与路径的交点为奇数个,那么豆豆能被围住,反之则不能
    如上
    证明:
    给每一条线规定内外
    那么每穿过一次就反转了多边形的内外
    若穿过奇数次,证明又回来了,所以在内部
    反之在外部

    代码参考网上

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    int q[11][11][1050], f[11][11], x[11], y[11], v[11], ans;
    int n, m, d, dx[4] = {1,-1,0,0}, dy[4] = {0,0,1,-1};
    
    struct haha{
        int a, b, c;
    }dou;
    
    int gc(int a,int b){
        char t = ' ';
        while(1){
            scanf("%c",&t); 
            if (t == '#') return -1;
            if (t >= '0' && t <= '9'){
                x[t - '0'] = a;
                y[t - '0'] = b;
                return t - '0';   
            } 
        }
    }
    
    queue<haha>p;
    int in[11][11][1050];
    
    inline void doit(int stx, int sty){
        memset(q, 0,sizeof(q ));
        memset(in, 0, sizeof(in));
        q[stx][sty][0] = 0;
        p.push({stx, sty, 0});
        int tx,ty,tz,tq,cross;
        while (!p.empty()){
            dou=p.front();p.pop();
            for (int dir=0;dir<4;dir++){
                tx=dou.a+dx[dir];ty=dou.b+dy[dir];
                if (tx<=0||ty<=0||tx>n||ty>m||f[tx][ty]!=0) continue;
                tz=dou.c;tq=q[dou.a][dou.b][dou.c]-1;
                if (dir<2){
                    cross=min(tx,dou.a);
                    for (int i=1;i<=d;i++){
                        if (x[i]!=cross||y[i]>ty) continue;
                        if (tz&(1<<(i-1)))
                            tq-=v[i];
                        else
                            tq+=v[i];
                        tz=tz^(1<<(i-1));
                    }
                }
                if (!in[tx][ty][tz]){
                    q[tx][ty][tz]=tq;
                    p.push({tx,ty,tz});
                    in[tx][ty][tz]=1;
                }
            }
        }
        for (int i=0;i<(1<<d);i++)
            if (in[stx][sty][i])
                ans=max(ans,q[stx][sty][i]);
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        scanf("%d",&d);
        for (int i=1;i<=d;i++)
        scanf("%d",&v[i]);
        for (int i=1;i<=n;i++){
            for (int j=1;j<=m;j++){
                f[i][j]=gc(i,j);
            }
        }
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                if (f[i][j]==0)
                    doit(i,j);
        printf("%d",ans);
    }
    
  • 相关阅读:
    Spark随机深林扩展—OOB错误评估和变量权重
    Spark随机森林实现学习
    RDD分区2GB限制
    Spark使用总结与分享
    Spark核心—RDD初探
    机器学习技法--学习笔记04--Soft SVM
    机器学习技法--学习笔记03--Kernel技巧
    机器学习基石--学习笔记02--Hard Dual SVM
    机器学习基石--学习笔记01--linear hard SVM
    特征工程(Feature Enginnering)学习记要
  • 原文地址:https://www.cnblogs.com/rui-4825/p/12705679.html
Copyright © 2011-2022 走看看