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;
}

原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/11634501.html

时间: 2024-12-13 23:51:45

Codeforces1214D. Treasure Island (dp + Hash)的相关文章

uva 10391 Compound Words (字符串-hash)

Problem E: Compound Words You are to find all the two-word compound words in a dictionary. A two-word compound word is a word in the dictionary that is theconcatenation of exactly two other words in the dictionary. Input Standard input consists of a

HNU 12868 Island (简单题)

题目链接:http://acm.hnu.cn/online/?action=problem&type=show&id=12868&courseid=272 解题报告:输入n*m的地图,+表示土地,-表示水,要你求这个海岛的海岸线有多长,扫一遍就可以了. 1 #include<cstdio> 2 const int maxn = 2000; 3 char map[maxn][maxn]; 4 int _x[4] = {-1,0,1,0}; 5 int _y[4] = {0

ZOJ 3209 Treasure Map (Dancing Links)

Treasure Map Time Limit: 2 Seconds      Memory Limit: 32768 KB Your boss once had got many copies of a treasure map. Unfortunately, all the copies are now broken to many rectangular pieces, and what make it worse, he has lost some of the pieces. Luck

UVA 10497 - Sweet Child Makes Trouble(DP+高精度)

题目链接:10497 - Sweet Child Makes Trouble 题意:n个物品,原来物品属于一个地方,现在要把物品重新放回去,问能放几种使得每个物品都与原来位置不同 思路:递推,一开始随便搞了个二维状态,dp[i][j]表示i个物品,有j个位置不同,那么dp[n][n]就是答案,递推式为: dp[i][j] = 1 (j == 0) dp[i][j] = (j - 1) * dp[i - 1][j - 1] + dp[i - 1][j] + (i - j + 1) * dp[i -

UVA 10641 - Barisal Stadium(DP + 几何)

题目链接:10641 - Barisal Stadium 题意:逆时针给定n个点,在给m个灯,每个灯有一个花费,要求最小花费使得所有边能被灯照到 思路:用向量叉积判断向量的顺逆时针关系,从而预处理出每个灯能照到的边,然后由于n个点是环的,所以可以直接扩大两倍,dp时候去枚举起点即可 状态为dp[i]表示现在照到i条边之前的边全部照亮需要的最小花费 代码: #include <stdio.h> #include <string.h> const double eps = 1e-6;

HDU 2577 How to Type(dp题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2577 解题报告:有一个长度在100以内的字符串,并且这个字符串只有大写和小写字母组成,现在要把这些字符串用键盘输入到电脑中,一开始的时候大写锁定是关闭的,并且要求结束的时候也是关闭的,然后让你求输入这些字符串最少需要按多少次键盘(包括Cap Lock键和Shift键) 一个典型的dp题,定义一个一维数组就够了,然后dp[i]的含义的输入到第i个字符时需要按键的最少次数.然后递推公式如下: dp[i]

hdu 4945 2048 (dp+组合数)

2048 Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 840    Accepted Submission(s): 199 Problem Description Teacher Mai is addicted to game 2048. But finally he finds it's too hard to get 2048.

POJ 1200 Crazy Search (字符串hash)

题目大意: 分析长度为n的子串有多少种. 思路分析: 对于没出现的字符,将其分配一个数字. 然后将子串看做一个nc进制的数. 然后hash判断. #include <cstdio> #include <iostream> #include <algorithm> #include <map> #include <cstring> #include <string> using namespace std; bool vis[26666

POJ 1473 There&#39;s Treasure Everywhere!(简单几何)

There's Treasure Everywhere! 博客原文地址:http://blog.csdn.net/xuechelingxiao/article/details/40865611 题目大意: 给你一个字符串,里面有许多的操作,前面的数字是移动的距离,后面的英文表示移动的方向,问最后从远点出发的一个点回落在什么地方以及距离出发点的距离是多少. 解题思路: 题目本身并不是很难,也没有什么坑点,没什么好说的,字符串处理的时候细心一点就行. PS:每组后面需要加一个回车,因为这个PE了一次