Treasure Island (bfs, dp, tarjan)

Posted by smeagal on Tue, 10 Sep 2019 14:47:27 +0200

In fact, there is another kind, I can't think of, I heard is running the smallest cut. tarjan's approach to bridge-finding is dead: the reason: dfs explode stacks too much

First of all, let's talk about bfs. Two bfs, the first BFS first finds the first path to n,m, and then marks the path. The second BFS is whether it can reach the end without this path. Yes, the answer is 2. No answer is 1. The first time BFS failed to find the path, the answer is 0.

[Code]

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e6+10;
int fa[N],vs[N];
vector<string>G;
string s;
vector<vector<int> >vis;
int n,m;
int dir[2][2]={1,0,0,1};
struct node
{
    int x,y;
};
int getid(int x,int y)
{return (x-1)*m+y;}

bool bfs()
{
    queue<node>que;
    que.push({1,1});
    vis[1][1]=1;
    bool flag=0;
    while(que.size())
    {
        node now=que.front();que.pop();
        if(now.x==n&&now.y==m) return 1;
        for(int i=0;i<2;++i)
        {
            int x=now.x+dir[i][0];
            int y=now.y+dir[i][1];
            if(x<1||x>n||y<1||y>m||G[x-1][y-1]=='#'||vs[getid(x,y)]) continue;
            if(vis[x][y]) continue;
            vis[x][y]=1;
            fa[getid(x,y)]=getid(now.x,now.y);
            que.push({x,y});
        }
    }
    return 0;
}
int main()
{
    cin>>n>>m;
    vis.resize(n+1);
    for(int i=0;i<=n;++i) vis[i].resize(m+1);
    rep(i,1,n)
    {
        cin>>s;
        G.pb(s);
    }
    if(!bfs()){printf("0");return 0;}
    rep(i,1,n) rep(j,1,m) vis[i][j]=0;
    int pre=getid(n,m);
    while(pre!=getid(1,1))
    {
        pre=fa[pre];
        vs[pre]=1;
    }
    if(bfs()) printf("2");
    else printf("1");
}

 

The second approach:

The second kind of learning comes from: https://blog.csdn.net/z472421519/article/details/100567224

There is no need to change any of the points that cannot be reached at the beginning.
(2) Because (n,m) (n,m)(n,m) point is in the lower left corner, we can only place (n_1,m) (n - 1,m)(n_1,m) and (n,m_1) (n,m - 1)(n,m - 1) (n,m_1) two to prevent him from reaching.
So just think about whether a single point can stop him.

We consider dp[i][j], dp1[i][j]dp[i][j], dp1[i][j]dp[i][j], dp1[i][j], dp1[i][j] two dp dpdp arrays, which have the following meanings:
dp[i][j]: How many walks are there from (1,1) to (i,j)
dp1[i][j]: how many walks are there from (n, m) (n, m) to (i,j) (i,j)(i,j), that is, from (i,j) (i,j)(i,j) to (n,m) (n,m)(n,m)
For a point, if dp1[i][j] DP [i] [j]= DP [n] [m] dp1[i][j] * DP [i] * DP [i]= DP [n] [m] dp1[i][j] DP [i] [j]= DP [n] [m], we can know that the point must be a necessary point according to the multiplication theorem.

At the same time, considering the problem of data range, we use the idea of hash to model the array. If in the sense of module a aa and module b bb, GCD (a, b) == 1 GCD (a, b) == 1 GCD (a, b) == 1, this point satisfies the equation above, then it is a necessary point.

The mechanism of cf makes the double hash card get some patience cards, so the code can refer to it.

[Code]

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
const ll m1 = 998244353, m2 = 1e9 + 7;
const int N=6e6+10;
ll dp1[N],dp2[N],dp3[N],dp4[N];
int n,m;
vector<string>G;
string s;
int getid(int x,int y){return (x-1)*m+y;}
ll add(ll &x ,ll y,ll mod)
{
    x=(x+y)%mod;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;++i)
    {
        cin>>s;G.push_back(s);
    }

    dp1[getid(1,1)]=dp2[getid(1,1)]=dp3[getid(n,m)]=dp4[getid(n,m)]=1ll;
    rep(i,1,n)
    rep(j,1,m)
    {
        if(G[i-1][j-1]=='.')
        {
            dp1[getid(i,j)]=(dp1[getid(i,j)]+dp1[getid(i-1,j)])%m1;
            dp1[getid(i,j)]=(dp1[getid(i,j)]+dp1[getid(i,j-1)])%m1;
            dp2[getid(i,j)]=(dp2[getid(i,j)]+dp2[getid(i-1,j)])%m2;
            dp2[getid(i,j)]=(dp2[getid(i,j)]+dp2[getid(i,j-1)])%m2;
        }
    }
    //printf("!!!!\n");
    for(int i=n;i>=1;--i)
    for(int j=m;j>=1;--j)
    {
        if(G[i-1][j-1]=='.')
        {
            add(dp3[getid(i,j)],dp3[getid(i+1,j)],m1);
            add(dp3[getid(i,j)],dp3[getid(i,j+1)],m1);
            add(dp4[getid(i,j)],dp4[getid(i+1,j)],m2);
            add(dp4[getid(i,j)],dp4[getid(i,j+1)],m2);
        }
    }
    if(dp1[getid(n,m)]==0&&dp2[getid(n,m)]==0)
    {
        printf("0\n");
        return 0;
    }
    rep(i,1,n)
    rep(j,1,m)
    {
        if(i==1&&j==1||i==n&&j==m) continue;
        if(G[i-1][j-1]=='.')
        {
            if(dp1[getid(i,j)]*dp3[getid(i,j)]%m1==dp1[getid(n,m)])
            {
                if(dp2[getid(i,j)]*dp4[getid(i,j)]%m2==dp2[getid(n,m)])
                {
                    printf("1\n");
                    return 0;
                }
            }
        }
    }
    printf("2\n");
}

 

Third kind: burst stack, no AC

#include<bits/stdc++.h>
using namespace std;
vector<string >ma;
string s;
int n,m;
const int N=6e6+10;
int dfn[N],low[N];
vector<vector<int> >vis;
struct node
{
    int x,y;
};
int dir[2][2]={1,0,0,1};
int cnt,ans;
struct edge
{
    int to,next;
}e[N];
int head[N],num;
void add(int u,int v)
{
    ++num;e[num]={v,head[u]};
    head[u]=num;

    ++num;e[num]={u,head[v]};
    head[v]=num;
}
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++cnt;
    printf("u:%d\n",u);
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa) continue;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            //If (dfn [root] < low [v]) ans +; / / number of bridges
            //If (low [v] > = DFN [root] & & u! = fa) the number of an1 + +// cut points
            if(dfn[u]<low[v]) ans=1;
        }
        else low[u]=min(low[u],dfn[v]);
    }
}
int getid(int x,int y)
{
    return (x-1)*m+y;
}
bool bfs()
{
    queue<node>que;
    que.push({1,1});
    vis[1][1]=1;
    bool flag=0;
    while(que.size())
    {
        node now=que.front();que.pop();
        if(now.x==n&&now.y==m) return 1;
        for(int i=0;i<2;++i)
        {
            int x=now.x+dir[i][0];
            int y=now.y+dir[i][1];
            if(x<1||x>n||y<1||y>m||ma[x-1][y-1]=='#') continue;
            if(vis[x][y]) continue;
            vis[x][y]=1;
            que.push({x,y});
        }
    }
    return 0;
}
int main()
{
    cin>>n>>m;
    vis.resize(n+2);
    for(int i=0;i<=n+1;++i) vis[i].resize(m+2);
    for(int i=1;i<=n;++i)
    {
        cin>>s;
        ma.push_back(s);
    }
    if(!bfs())
    {
        printf("0\n");return 0;
    }
    //printf("###\n");
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=m;++j)
        {
            if(i+1<=n&&ma[i-1][j-1]=='.'&&ma[i][j-1]=='.')
                add(getid(i,j),getid(i+1,j));
            if(j+1<=m&&ma[i-1][j-1]=='.'&&ma[i-1][j]=='.')
                add(getid(i,j),getid(i,j+1));
        }
    }
    //printf("what\n");
    ans=2;
    tarjan(getid(1,1),-1);
    printf("%d\n",ans);
}