• [swustoj 1095] 挖金子


     挖金子(1095)

    题目描述

    你在一个N*M的区域中,一开始在(1,1)的位置,每个位置有可能有金子,也有可能不能到达,也有可能有传送门。你只能往右或者下走,不能走出这个区域。当你位于传送门时,传送门你可以选择使用或者不使用,使用的次数无限,若使用则传送到传送门指定的位置。每个位置的金子你可以拿走它,问最后你最多能够拿走多少金子。

    输入

    首先测试数据组数T。

    对于每组测试数据,先输入两个整数N,M(2<=N,M<=40)。

    接下来是一个N*M的矩阵,表示每个位置的内容X,若0<=X<=9,表示该位置的金子个数为X,若X为'*',表示该位置有一个传送门,若X为'#',表示该位置不可到达。

    假设传送门的个数为K个,接下来K行,每行两个整数x,y(0<=x<n,0<=y<m),依次表示每个传送门传送的位置,顺序是从第一行开始从上到下扫描,每一行从左往右扫描。

    输出

    对于每组数据,输出能够得到的最多的金子的个数。

    样例输入

    1
    2 2
    11
    1*
    0 0

    样例输出

    3

     好累、- -

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define N 1610
    
    int n,m;
    int top;
    int bcnt;
    int Index;
    int dfn[N];
    int low[N];
    int stack[N];
    int belong[N];
    bool instack[N];
    vector<int> v1[N],v2[N];
    
    int tn,k;
    int dp[N];
    int gold[N];
    int mpt[45][45];
    int num[45][45];
    pair<int,int> p[N];
    int dir[2][2]={1,0,0,1};
    
    void init1()
    {
        k=tn=0;
        for(int i=0;i<n*m;i++){
            v1[i].clear();
            v2[i].clear();
        }
    }
    void init2()
    {
        top=-1;
        bcnt=Index=0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(instack,0,sizeof(instack));
    }
    void tarjan(int u,int pre)
    {
        int son=0,v;
        dfn[u]=low[u]=++Index;
        instack[u]=1;
        stack[++top]=u;
        for(int i=0;i<v1[u].size();i++){
            v=v1[u][i];
            if(!dfn[v]){
                son++;
                tarjan(v,u);
                if(low[u]>low[v]) low[u]=low[v];
            }
            else if(instack[v] && low[u]>dfn[v])
                low[u]=dfn[v];
        }
        if(dfn[u]==low[u]){
            bcnt++;
            do{
                v=stack[top--];
                instack[v]=0;
                belong[v]=bcnt;
            }while(v!=u);
        }
    }
    int dfs(int u)
    {
        if(dp[u]!=-1) return dp[u];
        dp[u]=gold[u];
        for(int i=0;i<v2[u].size();i++){
            int v=v2[u][i];
            dp[u]=max(dp[u],gold[u]+dfs(v));
        }
        return dp[u];
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            init1();
            for(int i=0;i<n;i++){ //编号
                for(int j=0;j<m;j++){
                    scanf(" %c",&mpt[i][j]);
                    if(mpt[i][j]!='#') num[i][j]=tn++;
                    if(mpt[i][j]=='*') p[k++]=make_pair(i,j);
                }
            }
            for(int i=0;i<k;i++){ //建图1
                int tx,ty;
                scanf("%d%d",&tx,&ty);
                v1[num[p[i].first][p[i].second]].push_back(num[tx][ty]);
            }
            for(int i=0;i<n;i++){ //建图2
                for(int j=0;j<m;j++){
                    if(mpt[i][j]=='#') continue;
                    for(int k=0;k<2;k++){
                        int tx=i+dir[k][0];
                        int ty=j+dir[k][1];
                        if(tx>=0 && tx<n && ty>=0 && ty<m && mpt[tx][ty]!='#')
                            v1[num[i][j]].push_back(num[tx][ty]);
                    }
                }
            }
            init2();
            for(int i=0;i<tn;i++){ //Tarjan
                if(!dfn[i]) tarjan(i,i);
            }
            memset(gold,0,sizeof(gold));
            for(int i=0;i<n;i++){ //计算金币
                for(int j=0;j<m;j++){
                    if(mpt[i][j]>='0' && mpt[i][j]<='9') gold[belong[num[i][j]]]+=mpt[i][j]-'0';
                }
            }
            for(int i=0;i<tn;i++){ //缩点建图
                for(int j=0;j<v1[i].size();j++){
                    if(belong[i]!=belong[v1[i][j]])
                        v2[belong[i]].push_back(belong[v1[i][j]]);
                }
            }
            memset(dp,-1,sizeof(dp));
            int ans=dfs(belong[0]); //记忆化搜索
            printf("%d
    ",ans);
        }
        return 0;
    }
    趁着还有梦想、将AC进行到底~~~by 452181625
  • 相关阅读:
    c++ 启发式搜索解决八数码问题
    基于linux或windows的c/s的循环服务器求一元二次方程的根
    基于linux或windows平台上的c/s简单通信
    第七章总结
    第六章总结
    第五章总结
    第四章总结
    第一章总结
    第三章总结
    第二章总结
  • 原文地址:https://www.cnblogs.com/hate13/p/4489766.html
Copyright © 2020-2023  润新知