poj3592 Instantaneous Transference tarjan缩点+建图

//给一个n*m的地图,坦克从(0 , 0)开始走
//#表示墙不能走,*表示传送门可以传送到指定地方,可以选择也可以选择不传送
//数字表示该格的矿石数,
//坦克从(0,0)开始走,只能往右和往下走,
//问最多能得到多少矿石
//直接建图,但由于有传送门,需要缩点
//然后用dfs直接搜一条权值最大的路
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
using namespace std ;
const int maxn = 2010 ;
int dfn[maxn] , low[maxn] , vis[maxn] , stack[maxn] ;int ans ;
int head[maxn*maxn] , belong[maxn] ,isstack[maxn] ;
int num , top , nedge , step ;int X[maxn] , Y[maxn] ; int n, m ;
int w[maxn];int a[maxn];int len;int visit[50][50];
int map[maxn][maxn] ;int pos ;
char str[maxn][maxn] ;
int dx[2] = {0,1} ;
int dy[2] = {1,0} ;
vector<int>vec[maxn] ;
struct Edge
{
    int v ;
    int next ;
}edge[maxn*maxn] ;
void addedge(int u , int v)
{
    edge[nedge].v = v ;
    edge[nedge].next = head[u] ;
    head[u] = nedge++ ;
}
void init()
{
    for(int i = 0;i <= n*m;i++)
    vec[i].clear() ;
    memset(head , -1 , sizeof(head)) ;
    memset(w ,0 , sizeof(w)) ;
    memset(dfn , 0 , sizeof(dfn)) ;
    memset(isstack ,0 , sizeof(isstack)) ;
    memset(map , 0 , sizeof(map)) ;
    memset(vis ,0 , sizeof(vis)) ;
    memset(a ,0 , sizeof(a)) ;
    num = top = nedge = step = len = 0 ;
}
void tarjan(int u)
{
    stack[++top] = u ;
    isstack[u] = 1 ;
    low[u] = dfn[u] = ++step ;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].v ;
        if(!dfn[v])
        {
            tarjan(v) ;
            low[u]  = min(low[u] , low[v]) ;
        }
        else if(isstack[v])
        low[u] = min(low[u] , dfn[v]) ;
    }
    if(low[u] == dfn[u])
    {
        num++ ;
        int v = -1 ;
        while(u != v)
        {
            v = stack[top--] ;
            isstack[v] = 0 ;
            belong[v] = num ;
            w[num] += a[v];
            if(v==0)pos = num ;
        }
    }
}
void build_tree()
{
    for(int i = 0;i <= n*m;i++)
      for(int j = head[i] ; j != -1 ; j =edge[j].next)
      {
          int u = belong[i] ;
          int v = belong[edge[j].v] ;
          if(u == v)continue ;
          vec[u].push_back(v) ;
          vis[v] = 1 ;
      }
}
int dfs(int u)
{
    int ma = 0 ;
    for(int i = 0;i < vec[u].size() ;i++)
    {
        int v = vec[u][i] ;
        ma = max(ma , dfs(v)) ;
    }
    ans = max(ans , ma+w[u]) ;
    return ma + w[u] ;
}
int main()
{
    //freopen("in.txt" , "r" , stdin) ;
    int t ;
    scanf("%d" , &t) ;
    while(t--)
    {
        scanf("%d%d" , &n , &m) ;
        init() ;
        ans = 0 ;
        for(int i = 0;i < n;i++)
        scanf("%s" ,str[i]) ;
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < m;j++)
             if(str[i][j] != ‘#‘)
             {
                if(str[i][j] == ‘*‘)
                {
                   X[++len] = i ;
                   Y[len] = j ;
                   a[i*m+j] = 0 ;
                }
                else
                {
                    a[i*m + j] = str[i][j] - ‘0‘ ;
                    ans = max(ans , a[i*m+j]) ;
                }
                for(int k = 0 ;k < 2;k++)
                {
                    int nx = i + dx[k] ;
                    int ny = j + dy[k] ;
                    if((nx >= n || ny >= m))
                    addedge(i*m + j , n*m) ;
                    else if(str[nx][ny] != ‘#‘)
                    addedge(i*m + j , nx*m + ny) ;
                }
             }
        }
        for(int i = 1;i <= len ;i++)
        {
            int u , v ;
            scanf("%d%d" , &u , &v) ;
            addedge(X[i]*m+ Y[i] , u*m+v) ;
        }
        pos = 0 ;
        for(int i = 0;i <= n*m;i++)
        if(head[i] != -1 && !dfn[i])
        tarjan(i) ;
        if(!pos)
        {
            cout<<ans<<endl;
            continue ;
        }
        build_tree() ;
        dfs(pos) ;
        printf("%d\n" ,ans) ;
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-09 19:40:50

poj3592 Instantaneous Transference tarjan缩点+建图的相关文章

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 2226 缩点建图+二分图最大匹配

这个最小覆盖但不同于 POJ 3041,只有横或者竖方向连通的点能用一块板子覆盖,非连续的,就要用多块 所以用类似并查集方法,分别横向与竖向缩点,有交集的地方就连通,再走一遍最大匹配即可 一开始还有点没想清楚缩点怎么写,其实就是横向和竖向分别缩一下,不要混在一起,否则很麻烦,要注意一下 #include <iostream> #include <cstdio> #include <cstring> using namespace std; char mat[900][9

【连通图|强连通分量+最长路】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

POJ 3592 Instantaneous Transference Tarjan+SPFA

题目大意:给出一张地图,有数字的点代表上面有数字个矿物,*代表这个点可以传送到另一个点上,#代表不能走.从一个点只能到这个点的下方和右方.现在从(0,0)开始,问最多可以收集多少矿物. 思路:这个题肯定是建图,然后最长路,关键是有了传送,就有可能形成正权环,然后在SPFA的过程中就会死循环.一个环上的所有权值只能得到一次,所以就用一次Tarjan求出所有的环,把权值累计一下,变成一个点,然后重新建图.这样得到的图就是拓扑图了,没有环,可以无忧无虑的SPFA了. PS:这个题我用拓扑排序怎么也切不

POJ3592 Instantaneous Transference 强连通+最长路

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

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

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

(tarjan/+DFS+反向建图) hdu 3639

G - Hawk-and-Chicken Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 3639 Description Kids in kindergarten enjoy playing a game called Hawk-and-Chicken. But there always exists a big problem: ev

[SDOI2010] 所驼门王的宝藏 [建图+tarjan缩点+DAG dp]

题面传送门: 传送门 思路: 看完题建模,容易得出是求单向图最长路径的问题 那么把这张图缩强联通分量,再在DAG上面DP即可 然而 这道题的建图实际上才是真正的考点 如果对于每一个点都直接连边到它所有的后继节点,那么可以被卡掉(1e5个点在同一行上) 考虑改变思路,运用网络流建图中的一个常用技巧:把横边和竖边映射成点,再从每个点向所在横坐标.纵坐标代表的点连边即可 这样会有2e6+1e5个点,但是tarjan算法效率O(n),完全无压力 自由(和谐)门的话,目前还没有比较好的方法解决 上网看了一

[bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑

5017: [Snoi2017]炸弹 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 608  Solved: 190[Submit][Status][Discuss] Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi?Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在,请你帮忙计算一下,先把第 i 个炸弹引爆,将引爆多少个炸弹呢? Inp