标签:
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 ; }
poj3592--Instantaneous Transference(强连通缩点+spfa)
标签:
原文地址:http://blog.csdn.net/winddreams/article/details/45769533