zoukankan      html  css  js  c++  java
  • 51nod1580铺管道

    这题的难点在于理解题目和脑洞。

    其实我一开始以为这道题是插头DP。原题让我们求的就是各类折线(折两次的,折一次的)以及直直的切线。

    代码其实不复杂,画个图理解一下

    具体就一下四种情况

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int MAXN = 2005;
    int n, m;
    char S[MAXN];
    bool A[MAXN][MAXN], B[MAXN][MAXN];
    bool D[MAXN][MAXN], U[MAXN][MAXN];
    long long ans = 0;
    void solve(bool T[][MAXN], int n, int m, int flag)
    {
        memset(D, 0, sizeof(D));
        memset(U, 0, sizeof(U));
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                D[i][j] = D[i - 1][j] | T[i][j];    //  是否可以从 T[i - 1][j] 向下到达 T[i][j] 其实是是否可以从T[i][1]向下到达T[i][j] 0表示可以
            }
        }
        for (int i = n; i; i--)
        {
            for (int j = 1; j <= m; j++)
            {
                U[i][j] = U[i + 1][j] | T[i][j];    //  是否可以从 T[i + 1][j] 向上到达 T[i][j] 其实是是否可以从T[n][j]向上到达T[i][j] 0表示可以
            }
        }
        for (int i = 2; i < n; i++)
        {
            int tmp = 0;
            if (!T[i][1] && flag)
            {
                tmp = 1;
            }
            D[i][1] = U[i][1] = 1;
            for (int j = 2; j < m; j++)
            {
                if (T[i][j])
                {
                    tmp = 0;
                    continue;
                }
                ans += ((!D[i][j]) + (!U[i][j])) * tmp; //  算 上+[右…右]+下 和 下+[右…右]+上
                                                        //  和 上+[右…右]+上 和 下+[右…右]+下
                                                        //  以及 从第一列开始 [右…右]+上 和 [右…右]+下 的折线的个数//左上,右上
                ans += (!D[i][j] && !U[i][j - 1]) + (!U[i][j] && !D[i][j - 1]); //  算 上+右+上 和 下+右+下 //左上角那张
                tmp += (!D[i][j - 1]) + (!U[i][j - 1]); //  算 能到达第 i 行的部分数配合下一次循环使用
            }
            if (!T[i][m] && flag)
            {
                ans += tmp + (!D[i][m - 1]) + (!U[i][m - 1]);   //  算 从前边任何一列开始 下+[右…右]
                                                              //  和 上+[右…右] 的情况 以及 左右两端 直达的情况
            }
        }
        if (flag)
        {
            for (int j = 2; j < m; j++)
            {
                ans += (!D[n][j]);  //  算 上下两端 直达的情况
            }
        }
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
    
        for (int i = 1; i <= n; i++)
        {
            scanf("%s", S + 1);
            for (int j = 1; j <= m; j++)
            {
                A[i][j] = S[j] == '#';
            }
        }
        solve(A, n, m, 1);
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                B[j][i] = A[i][j];
            }
        }
        solve(B, m, n, 0);
        printf("%lld
    ", ans);
     
      return 0;
    }
    代码转自http://blog.csdn.net/f_zyj/article/details/72909671
  • 相关阅读:
    Anagram
    HDU 1205 吃糖果(鸽巢原理)
    Codeforces 1243D 0-1 MST(补图的连通图数量)
    Codeforces 1243C Tile Painting(素数)
    Codeforces 1243B2 Character Swap (Hard Version)
    Codeforces 1243B1 Character Swap (Easy Version)
    Codeforces 1243A Maximum Square
    Codeforces 1272E Nearest Opposite Parity(BFS)
    Codeforces 1272D Remove One Element
    Codeforces 1272C Yet Another Broken Keyboard
  • 原文地址:https://www.cnblogs.com/dancer16/p/7351701.html
Copyright © 2011-2022 走看看