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
  • 相关阅读:
    hdu5360 Hiking(水题)
    hdu5348 MZL's endless loop(欧拉回路)
    hdu5351 MZL's Border(规律题,java)
    hdu5347 MZL's chemistry(打表)
    hdu5344 MZL's xor(水题)
    hdu5338 ZZX and Permutations(贪心、线段树)
    hdu 5325 Crazy Bobo (树形dp)
    hdu5323 Solve this interesting problem(爆搜)
    hdu5322 Hope(dp)
    Lightoj1009 Back to Underworld(带权并查集)
  • 原文地址:https://www.cnblogs.com/luyingfeng/p/3553645.html
Copyright © 2011-2022 走看看