zoukankan      html  css  js  c++  java
  • POJ 3592 Instantaneous Transference(强联通分量 Tarjan)

    http://poj.org/problem?id=3592

    题意 :给你一个n*m的矩阵,每个位置上都有一个字符,如果是数字代表这个地方有该数量的金矿,如果是*代表这个地方有传送带并且没有金矿,可以传送到指定的位置,如果是#代表该位置不可走,初始位置在左上角,只能向下或向右走,并且走到传送带的时候可选择是否传送。问当走出去的时候能获得的最大近况数是多少。

    思路 :先将二维矩阵转化成一维的点建图,可以向下向右建图,而且传送带也可以建边,缩点之后再建边,最后用spfa求最长路。

    #include <iostream>
    #include <stdio.h>
    #include <queue>
    #include <string.h>
    
    using namespace std;
    
    const int maxn = 555555 ;
    const int INF = -1000000000 ;
    
    int belong[maxn],instack[maxn],dfn[maxn],low[maxn],g[maxn],map[maxn],c[maxn] ;
    //belong[i]指的是i点所在的联通分量的编号。instack模拟的是栈,因为每个节点是要入栈的,来判断是否属于同一个分量
    //dfn[i]为搜索i结点的次序编号,Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。
    //g[i]是指将一个矩阵从0到n*m编号之后的,i点所在的那个位置的宝藏数,map[i]记录的是第i个传送带的位置
    //c[i]记录的是第i个联通分量中宝藏的总数。
    int cntt,cnt,top,bcc_clock,cntb,n,m,num ;
    int head1[maxn] ,head[maxn];
    char point[100][100] ;//输入的地图
    int dis[maxn],coun[maxn],index ;
    bool vis[maxn],flag[maxn] ;
    int dire[2][2] = {{0,1},{1,0}} ;
    
    struct node
    {
        int u,v,w,next ;
    } p[maxn] ,ch[maxn];
    
    void addedge(int u,int v)
    {
        p[cnt].u = u ;
        p[cnt].v = v ;
        p[cnt].next = head[u] ;
        head[u] = cnt++ ;
    }
    
    void addnode(int u,int v,int w)
    {
        ch[cntt].u = u ;
        ch[cntt].v = v ;
        ch[cntt].w = w ;
        ch[cntt].next = head1[u] ;
        head1[u] = cntt++ ;
    }
    
    void tarjan(int u)
    {
        vis[u] = true ;
        dfn[u] = low[u] = ++bcc_clock ;
        instack[++top] = u ;
        for(int i = head[u] ; i+1 ; i = p[i].next)
        {
            int v = p[i].v ;
            if(!dfn[v])
            {
                tarjan(v) ;
                low[u] = min(low[u],low[v]) ;
            }
            else if(vis[v])
                low[u] = min(low[u],dfn[v]) ;
        }
        if(dfn[u] == low[u])
        {
            cntb++ ;
            int v ;
            do
            {
                v = instack[top--] ;
                vis[v] = false ;
                belong[v] = cntb ;
            }
            while(v != u) ;
        }
    }
    
    void Init()
    {
        memset(dfn,0,sizeof(dfn)) ;
        memset(low,0,sizeof(low)) ;
        memset(belong,0,sizeof(belong)) ;
        memset(c,0,sizeof(c)) ;
        memset(vis,0,sizeof(vis)) ;
    num = 0 ;
        memset(head,-1,sizeof(head)) ;
        memset(head1,-1,sizeof(head1)) ;
        cnt = 0,top = 0 ,cntb = 0,bcc_clock = 0,cntt = 0 ;
    }
    
    bool relax(int u,int v,int w)
    {
        if(dis[v] < dis[u] + w)
        {
            dis[v] = dis[u] + w ;
            return true ;
        }
        return false ;
    }
    
    bool spfa(int u)
    {
        memset(flag,false,sizeof(flag)) ;
        memset(coun,0,sizeof(coun)) ;
        flag[u] = true ;
        for(int i = 0 ; i <= cntb ; i++)
            dis[i] = INF ;
        queue<int >Q ;
        Q.push(u) ;
        dis[u] = 0 ;
        while(!Q.empty ())
        {
            int st = Q.front() ;
            Q.pop() ;
            flag[st] = false ;
            for(int i = head1[st] ; i+1 ; i = ch[i].next)
            {
                if(relax(st,ch[i].v,ch[i].w) && !flag[ch[i].v])
                {
                    if((++coun[ch[i].v]) > m*n) return false ;
                    Q.push(ch[i].v) ;
                    flag[ch[i].v] = true ;
                }
            }
        }
        index = 0 ;
        for(int i = 1 ; i <= cntb ; i++)
            index = max(index,dis[i]) ;
        return true ;
    }
    int main()
    {
        int T ;
        scanf("%d",&T) ;
        while(T--)
        {
            scanf("%d %d",&n,&m) ;
            int cnnt = 0;//记录传送带的个数
            Init() ;
            getchar() ;
            for(int i = 0 ; i < n ; i++)
                scanf("%s",point[i]) ;
            for(int i = 0 ; i < n ; i++)
            {
                for(int j = 0 ; j < m ; j++)
                {
                    int k = i*m+j ;
                    if(point[i][j] == '#')
                    {
                        g[k] = -1 ;
                        continue ;
                    }
                    else
                    {
                        if(point[i][j] == '*')
                        {
                            map[cnnt++] = k ;
                            g[k] = 0 ;
                        }
                        else if(point[i][j] >= '0' && point[i][j] <= '9')
                            g[k] = point[i][j] - '0' ;
                        for(int ii = 0 ; ii < 2 ; ii++)
                        {
                            int xx = i+dire[ii][0] ;
                            int yy = j+dire[ii][1] ;
                            if(xx < n && yy < m)
                            {
                                if(point[xx][yy] != '#')
                                    addedge(k,xx*m+yy) ;
                            }
                        }
                    }
                }
            }
            for(int i = 0 ; i < cnnt ; i++)
            {
                int x,y ;
                scanf("%d %d",&x,&y) ;
                if(point[x][y] != '#')
                    addedge(map[i],x*m+y) ;
            }
           // Init() ;
            for(int i = 0 ; i < n*m ; i++)
                if(!dfn[i]) tarjan(i) ;
            for(int i = 0 ; i < n*m ; i++)
                c[belong[i]] += g[i] ;
            addnode(0,belong[0],c[belong[0]]);//缩点之后的建边
            for(int i = 0 ; i < n*m ; i++)
            {
                for(int j = head[i] ; j + 1 ; j = p[j].next)
                {
                    int v = p[j].v ;
                    if(belong[i] != belong[v])
                    {
                        addnode(belong[i],belong[v],c[belong[v]]) ;//两个点不属于同一个联通分量
                    }
                }
            }
            spfa(0) ;//求最长路
            printf("%d
    ",index) ;
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(13)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(12)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(11)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(10)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(9)
    【Spark亚太研究院系列丛书】Spark实战高手之路-第一章 构建Spark集群(第五步)(8)
    获取文件CRC和MD5
    Delphi系统托盘组件 TTrayIcon 简介
    如何调试delphi的Access violation at address错误
    Eclipse导入Gradle时报错:SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable
  • 原文地址:https://www.cnblogs.com/luyingfeng/p/3553645.html
Copyright © 2011-2022 走看看