poj3592--Instantaneous Transference(强连通缩点+spfa)

poj3592:题目链接

题目大意:给出n*m的矩阵,其中数字代表矿物的数量,#代表不可达,*代表传送门,传送到给定的位置。问最多可以收集多少矿物(每个矿物只能被收集一次,可以经过多次)

因为存在传送门,所以就会形成环,用强连通将形成环的缩成一个点,记录每个点代表的矿物数,最后用spfa找出最长路,也就是可以得到的最多的矿物数。(不会出现矩阵外的点)

#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <algorithm>
using namespace std ;
struct node
{
    int u , v ;
    int next ;
} edge[10000] , tree[10000] ;
char Map[50][50] ;
int head[2000] , h_tree[2000] , cnt ;
int low[2000] , dnf[2000] , time ;
int vis[2000] , belong[2000] , num ;
int sum[2000] , n , m , dis[2000];
stack <int> sta ;
queue <int> que ;
void init()
{
    cnt = time = num = 0 ;
    while( !sta.empty() ) sta.pop() ;
    while( !que.empty() ) que.pop() ;
    memset(head,-1,sizeof(head)) ;
    memset(h_tree,-1,sizeof(head)) ;
    memset(low,0,sizeof(low)) ;
    memset(dnf,0,sizeof(dnf)) ;
    memset(vis,0,sizeof(vis)) ;
    memset(belong,0,sizeof(belong)) ;
    memset(sum,0,sizeof(sum)) ;
    memset(Map,0,sizeof(Map)) ;
}
void add(int u,int v)
{
    edge[cnt].u = u ;
    edge[cnt].v = v ;
    edge[cnt].next = head[u] ;
    head[u] = cnt++ ;
}
void add_tree(int u,int v)
{
    tree[cnt].u = u ;
    tree[cnt].v = v ;
    tree[cnt].next = h_tree[u] ;
    h_tree[u] = cnt++ ;
}
void tarjan(int u)
{
    dnf[u] = low[u] = ++time ;
    vis[u] = 1 ;
    sta.push(u) ;
    int i , v , j ;
    for( i = head[u] ; i != -1 ; i = edge[i].next )
    {
        v = edge[i].v ;
        if( !dnf[v] )
        {
            tarjan(v) ;
            low[u] = min(low[u],low[v]) ;
        }
        else if( vis[v] )
        {
            low[u] = min(low[u],dnf[v]) ;
        }
    }
    if( low[u] == dnf[u] )
    {
        ++num ;
        while( 1 )
        {
            j = sta.top() ;
            sta.pop() ;
            vis[j] = 0 ;
            belong[j] = num ;
            if( Map[j/m][j%m] != '*' )
                sum[num] += Map[j/m][j%m] - '0' ;
            if(j == u) break ;
        }
    }
}
int spfa(int u)
{
    memset(vis,0,sizeof(vis)) ;
    memset(dis,-1,sizeof(dis)) ;
    dis[u] = sum[u] ;
    vis[u] = 1 ;
    que.push(u) ;
    int i , v , max1 = sum[u] ;
    while( !que.empty() )
    {
        u = que.front() ;
        que.pop() ;
        vis[u] = 0 ;
        for(i = h_tree[u] ; i != -1 ; i = tree[i].next)
        {
            v = tree[i].v ;
            if( dis[v] < dis[u] + sum[v] )
            {
                dis[v] = dis[u] + sum[v] ;
                max1 = max(max1,dis[v]) ;
                if( !vis[v] )
                {
                    vis[v] = 1 ;
                    que.push(v) ;
                }
            }
        }
    }
    return max1 ;
}
int main()
{
    int t , i , j ;
    int u , v , k ;
    scanf("%d", &t) ;
    while( t-- )
    {
        init() ;
        scanf("%d %d", &n, &m) ;
        for(i = 0 ; i < n ; i++)
            scanf("%s", Map[i]) ;
        for(i = 0 ; i < n ; i++)
        {
            for(j = 0 ; j < m ; j++)
            {
                if( Map[i][j] == '#' ) continue ;
                if( Map[i][j] == '*' )
                {
                    scanf("%d %d", &u, &v) ;
                    if(u < n && v < m && Map[u][v] != '#' )
                        add(i*m+j,u*m+v) ;
                }
                if( i < n-1 && Map[i+1][j] != '#' )
                    add(i*m+j,(i+1)*m+j) ;
                if( j < m-1 && Map[i][j+1] != '#' )
                    add(i*m+j,i*m+j+1) ;
            }
        }
        for(i = 0 ; i < n*m ; i++)
            if( !dnf[i] && head[i] != -1 ) tarjan(i) ;
        for(i = 0 , cnt = 0 ; i < n*m ; i++)
            for(j = head[i] ; j != -1 ; j = edge[j].next)
            {
                u = belong[ edge[j].u ] ;
                v = belong[ edge[j].v ] ;
                if( u != v )
                    add_tree(u,v) ;
            }
        printf("%d\n", spfa( belong[0] ) ) ;
    }
    return 0 ;
}
时间: 2024-12-20 01:07:49

poj3592--Instantaneous Transference(强连通缩点+spfa)的相关文章

POJ3592 Instantaneous Transference 强连通+最长路

题目链接: poj3592 题意: 给出一幅n X m的二维地图,每个格子可能是矿区,障碍,或者传送点 用不同的字符表示: 有一辆矿车从地图的左上角(0,0)出发,只能往右走或往下走,或者通过传送点  选择是否 传送到特定地点 采过的矿的格子 矿会消失;问这辆矿车最多能采多少矿 解题思路: 首先重新建图,将图中二维的顶点压缩成一维的顶点             (方便Tarjan算法) 每个顶点往右,下的顶点建边,传送点的格子往特定顶点建边(建边的两端不能有障碍) 得到一幅可能存在环的有向图;

poj3592 Instantaneous Transference tarjan缩点+建图

//给一个n*m的地图,坦克从(0 , 0)开始走 //#表示墙不能走,*表示传送门可以传送到指定地方,可以选择也可以选择不传送 //数字表示该格的矿石数, //坦克从(0,0)开始走,只能往右和往下走, //问最多能得到多少矿石 //直接建图,但由于有传送门,需要缩点 //然后用dfs直接搜一条权值最大的路 #include<cstdio> #include<cstring> #include<iostream> #include<vector> #inc

poj 3592 Instantaneous Transference 强连通图 缩点 再求最长路

1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<stack> 5 #include<queue> 6 using namespace std; 7 #define maxx 44 8 #define maxx2 44*44 9 #define INF 99999999 10 char s[maxx][maxx]; 11 bool tong[maxx2

【连通图|强连通分量+最长路】POJ-3592 Instantaneous Transference

Instantaneous Transference Time Limit: 5000MS Memory Limit: 65536K Description It was long ago when we played the game Red Alert. There is a magic function for the game objects which is called instantaneous transfer. When an object uses this magic fu

POJ3592 Instantaneous Transference【强连通分量】【最长路】

题目链接: http://poj.org/problem?id=3592 题目大意: 有一个N*M的矩阵地图,矩阵中用了多种字符代表不同的地形,如果是数字X(0~9),则表示 该区域为矿区,有X单位的矿产.如果是"*",则表示该区域为传送点,并且对应唯一一个目标 坐标.如果是"#",,则表示该区域为山区,矿车不能进入.现在矿车的出发点在坐标(0,0)点. 并且(0,0)点一定不是"#"区域.矿车只能向右走.向下走或是遇到传送点的时候可以传送到 指

poj3114--Countries in War(强连通缩点+spfa)

poj3114:题目链接 .题目大意:给出n个城市,m条送信的渠道,u v w代表u城市送信到v城市需要w小时.同时如果两个城市属于一个国家,那么送信时间为0,在一个国家中的条件是所有城市相互之间可以送信到达. 强连通找出连通块,那么每个连通块就是一个国家,缩点,重新建图,spfa找出要求的最短路径 #include <cstdio> #include <cstring> #include <stack> #include <queue> #include

POJ 3592 Instantaneous Transference(强连通+DP)

POJ 3592 Instantaneous Transference 题目链接 题意:一个图,能往右和下走,然后有*可以传送到一个位置,'#'不能走,走过一个点可以获得该点上面的数字值,问最大能获得多少 思路:由于有环先强连通缩点,然后问题转化为dag,直接dp即可 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #include <sta

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA

[BZOJ 1179]ATM题解 Tarjan缩点+SPFA Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,

Light OJ 1168 Wishing Snake 强连通缩点+哈密顿通路

题目来源:Light OJ 1168 Wishing Snake 题意:有点难看懂题意 看了一个小时再加别人的代码才懂意思 从0开始 输入的那些每一对u v 都要经过 就是从0到到达那些点 思路:首先缩点 每一个强连通分量里面的点都是可达的 缩点后的图是有向无环图 如果从0这个强连通分量可以出去到2个强连通分量 那么这两个强连通分量是不可能相互可达 所以可行的方案就是所有的强连通分量连成一线 一个一个串起来 除了第一个 出度是1入度是0和最后一个出度是0入度是1 其他都是入度等于出度是1 特判只