zoukankan      html  css  js  c++  java
  • 【题解】SCOI2009围豆豆

      很久之前就很想做的一道题,一直思考到今天才下定决心看题解。这道题中,很关键的一点就在于:如何判断一个点是否在一个多边形内?其实如果计算几何基本功扎实的话,应该是可以很快给出答案的(可惜我完全不行):由一个点向一边引一条射线,判断与多边形相交的边数。若边数是奇数,说明在多边形的内部。在这里贴一篇博文:大佬的博客

      以下想图解一下射线法(与代码判图方式一致)。

      1.图中五角星为一个豆豆。

      2.在转移的时候,我们由(f[i][j][k] -> f[i][j + 1][k']) 的转移即为在这两个格子之间链接一条边界线。

     

      3.再转移一下,我们会注意到此时这个豆豆向下引的射线与两条边界线均有交点,但它暂时是被包围的状态,与我们所设的状态矛盾。所以我们规定:只有与箭头头部相交才算做一次。

      4.如果再次出现,次数变成偶数,就不在边界内了:

      通过这几幅图,我们会发现竖直方向的移动不会改变豆豆是否被包围的判定,可以不必重复判断。了解了这一点之后,我们每一次的转移都是在画轮廓线。我们规定状态 (f[i][j][k]) 表示当前边界线画到第 (left ( i,j ight ))时,被包围的豆豆状况为 (k) 时的最大得分。因为 (left ( i,j ight )) 可以转移到 (left ( i,j + 1 ight )),反之亦然,所以这个转移是不满足拓扑序的。但由于它满足三角形不等式,所以我们使用spfa来转移状态。由于题目规定移动会减少分数,所以不用担心存在正环的问题。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 20
    #define maxk 6000
    #define INF 99999999
    int n, m, S, Map[maxn][maxn];
    int ans, CNST, val[maxn];
    int f[maxn][maxn][maxk];
    const int dx[4]={0, 0, -1, 1};
    const int dy[4]={-1, 1, 0, 0};
    bool vis[maxn][maxn][maxk];
    
    struct node 
    {
        int x, y, num;
        node(int xx = 0, int yy = 0, int zz = 0) { x = xx, y = yy, num = zz; }
    }; queue <node> q;
    node p[maxn];
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void spfa(int sx, int sy)
    {
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
                for(int k = 0; k < CNST; k ++)
                    f[i][j][k] = -INF;
        q.push(node(sx, sy, 0)), f[sx][sy][0] = 0, vis[sx][sy][0] = 1;
        while(!q.empty())
        {
            node now = q.front(); q.pop();
            vis[now.x][now.y][now.num] = 0;
            if(now.x == sx && now.y == sy)
                ans = max(ans, f[now.x][now.y][now.num]);
            for(int k = 0; k < 4; k ++)
            {
                int xx = now.x + dx[k], yy = now.y + dy[k];
                if(xx <= 0 || xx > n || yy <= 0 || yy > m || Map[now.x][now.y]) continue;
                int num = now.num, Y = max(yy, now.y), del = 0;
                if(k <= 1)
                {
                    for(int i = 1; i <= S; i ++)
                        if(p[i].y == Y && p[i].x < xx) 
                        {
                            num ^= 1 << (i - 1);
                            if((num >> i - 1) & 1) del += val[i];
                            else del -= val[i];
                        }
                }
                if(f[xx][yy][num] < f[now.x][now.y][now.num] + del - 1)
                {
                    f[xx][yy][num] = f[now.x][now.y][now.num] + del - 1;
                    if(!vis[xx][yy][num]) vis[xx][yy][num] = 1, q.push(node(xx, yy, num));
                }
            }
        }
    }
    
    int main()
    {
        n = read(), m = read(), S = read();
        CNST = (1 << S) - 1;
        for(int i = 1; i <= S; i ++) val[i] = read();
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
            {
                char c; cin >> c;
                if(c == '#') Map[i][j] = -1;
                else Map[i][j] = c - '0';
                if(Map[i][j] >= 1) p[Map[i][j]] = node(i, j);
            }
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= m; j ++)
                if(!Map[i][j]) spfa(i, j);
        printf("%d
    ", ans);
        return 0; 
    } 

     

  • 相关阅读:
    自定义 spark transformer 和 estimator 的范例
    spark 与 scikit-learn 机器学习流程组件设计哲学比较
    命名空间和作用域
    FeatureUnion 与 ColumnTransformer 关系
    注解与装饰器
    装饰器编写--要点
    闭包结构的本质
    SQL 自动增长 identity
    SQL 基本的函数
    int和long long有符号整形 负数比正数多一个
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9122212.html
Copyright © 2011-2022 走看看