POJ 3592 Instantaneous Transference
强连通分量
题意:一个n行m列的矩阵图,上面有3种点,可能是数字x(0<=x<=9),表示这里有多少个矿石,#表示不能走到这点,*表示传送点,对应一个目标点,可以瞬间传送到目标点。你从(0,0)左上角处出发,行走的方向只能是向左或者向下,要求你走到某个地方(不一定是右下角),让你得到的矿石最多。一个地方的矿石只能采集一次,下次再去到那个点是没有矿石的。注意几点,传送点可能将你传送到#这种点,那么相当于这个传送点是多余的等于没用,另外在传送点可以选择传送或者不传送继续走。
分析:由于传送点的存在,可能使这个有向图构成环,进而可能产生强连通分量,所以先建图,进行一次强连通分量缩点,为什么缩点,因为易知,在一个强连通分量内的点都是可以全部到达的,所以这个点内的矿石都能采集到。缩点后得到一个DAG,对这个DAG重新建图,另外重新计算缩点后每个点有多少矿石(即原来小点的矿石和)。然后从点(0,0)缩点后所在那个大点出发,用BFS搜索,求一次最长路,再取最大值即可
总体来说这题不难,代码量,对于图论的题来讲,也差不多是这么多了,写的时候状态不好,很多小bug,调试很久wa了好几次才过。
这题总的来说也不算难,就Tarjan缩点+bfs搜索最长路
#include <iostream> #include <cstdio> #include <cstring> #include <utility> #include <vector> #include <stack> #include <queue> using namespace std; #define N 2100 char a[50][50]; vector<int>mp; vector<int>e[N]; vector<int>ver[N]; stack<int>sta; queue<int>que; int row,col,n; int dfn[N],low[N],belong[N],dcnt,bcnt; int val[N],sv[N],d[N]; bool ins[N],inq[N]; void input() { cin >> row >> col; n = row * col; for(int i=0; i<n; i++) e[i].clear(); for(int r=0; r<row; r++) cin >> a[r]; for(int r=0; r<row; r++) for(int c=0; c<col; c++) if(a[r][c] != '#') { int x,y,v,u; u = r * col + c; if(r+1 < row && a[r+1][c] != '#') { v = (r+1) * col + c; e[u].push_back(v); } if(c+1 < col && a[r][c+1] != '#') { v = r * col + c+1; e[u].push_back(v); } if(a[r][c] >= '0' && a[r][c] <= '9') val[u] = a[r][c] - '0'; else { val[u] = 0; cin >> x >> y; if(a[x][y] != '#') { v = x * col + y; e[u].push_back(v); } } } } void rebuild() { for(int i=1; i<=bcnt; i++) ver[i].clear(); for(int i=0; i<n; i++) { int u = belong[i]; for(int j=0; j<e[i].size(); j++) { int v = belong[e[i][j]]; if(u != v) ver[u].push_back(v); } } } void dfs(int u) { dfn[u] = low[u] = ++dcnt; sta.push(u); ins[u] = true; for(int i=0; i<e[u].size(); i++) { int v = e[u][i]; if(!dfn[v]) { dfs(v); low[u] = min(low[u] , low[v]); } else if(ins[v]) low[u] = min(low[u] , dfn[v]); } if(low[u] == dfn[u]) { ++bcnt; sv[bcnt] = 0; while(true) { int x = sta.top(); sta.pop(); ins[x] = false; belong[x] = bcnt; sv[bcnt] += val[x]; if(x == u) break; } } } void Tarjan() { dcnt = bcnt = 0; memset(dfn,0,sizeof(dfn)); memset(ins,false,sizeof(ins)); for(int i=0; i<n; i++) if(!dfn[i]) dfs(i); } void bfs() { while(!que.empty()) que.pop(); memset(inq,false,sizeof(inq)); memset(d,-1,sizeof(d)); int s = belong[0]; d[s] = sv[s]; que.push(s); inq[s] = 1; while(!que.empty()) { int u = que.front(); que.pop(); inq[u] = 0; for(int i=0; i<ver[u].size(); i++) { int v = ver[u][i]; if(d[v] < d[u] + sv[v]) { d[v] = d[u] + sv[v]; if(!inq[v]) { inq[v] = 1; que.push(v); } } } } } int main() { int cas; cin >> cas; while(cas--) { input(); Tarjan(); rebuild(); bfs(); int res = 0; for(int i=1; i<=bcnt; i++) res = max(res , d[i]); cout << res << endl; } return 0; }