Dancepted

Dancing Acceped!

Codeforces1214D. Treasure Island (dp + Hash)

题目链接:传送门


 

思路:

仔细观察可以发现,答案最多就是2,只要把(2,1)和(1,2)堵住就可以了。

答案是0的情况就是初始状态下,(1,1)就已经不可达(n,m)了,很好判断。

所以重点就是区分答案为1和答案为2的情况。

如果答案为1的话,就说明从(1,1)到(n,m)的所有路径都经过同一个点(这样的点至少一个)。

实际上,求出(1,1)出发可达的所有点的集合S1,和所有可达(n,m)的点S2。这里用dp来跑可以O(nm)。其中坐标要压成一维的(因为n、m的范围没有给出),否则不好开内存。

再以到(1,1)的曼哈顿距离相同为条件,把两个点集划分成O(n+m)个集合。

这些集合的大小的最小值,就是答案。


 

代码:O(nm)

#include <bits/stdc++.h>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 1000005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

int n, m;
inline int getx(int t) {
    return t / m;
}
inline int gety(int t) {
    return t % m;
}
inline int gett(int x, int y) {
    return x*m + y;
}

char s[N];
bool vis11[N], visnm[N];
int main()
{
    cin >> n >> m;
    memset(vis11, false, sizeof vis11);
    memset(visnm, false, sizeof visnm);
    for (int i = 0; i < n; i++)
        scanf("%s", s + i*m);
    vis11[0] = visnm[n*m-1] = true;
    for (int t = 1; t < n*m-1; t++) {
        int x = getx(t), y = gety(t);
        if (s[t] == '#') continue;
        if (x == 0) {
            int pret = gett(x, y-1);
            vis11[t] = vis11[pret];
        }
        else if (y == 0) {
            int pret = gett(x-1, y);
            vis11[t] = vis11[pret];
        }
        else {
            int pret1 = gett(x, y-1);
            int pret2 = gett(x-1, y);
            vis11[t] = vis11[pret1] || vis11[pret2];
        }
    }
    for (int t = n*m-2; t > 0; t--) {
        int x = getx(t), y = gety(t);
        if (s[t] == '#')
            continue;
        if (x == n-1) {
            int pret = gett(x, y+1);
            visnm[t] = visnm[pret];
        }
        else if (y == m-1) {
            int pret = gett(x+1, y);
            visnm[t] = visnm[pret];
        }
        else {
            int pret1 = gett(x, y+1);
            int pret2 = gett(x+1, y);
            visnm[t] = visnm[pret1] || visnm[pret2];
        }
    }
    int ans = 2;
    for (int d = 1; d < n+m-2; d++) {
        int x = 0, y = d;
        if (y >= m) {
            y = m-1;
            x = d-y;
        }
        int cnt = 0;
        for (; x < n && y >= 0; x++, y--) {
            int tmpt = gett(x, y);
            if (vis11[tmpt] && visnm[tmpt])
                cnt++;
        }
        if (cnt == 0) {
            ans = 0;
            break;
        }
        if (cnt == 1)
            ans = 1;
    }
    cout << ans << endl;
    return 0;
}
View Code

 

posted on 2019-10-08 11:36  Danceped  阅读(221)  评论(3编辑  收藏  举报

导航