POJ 3592 Instantaneous Transference(强连通+DP)

POJ 3592 Instantaneous Transference

题目链接

题意:一个图,能往右和下走,然后有*可以传送到一个位置,‘#‘不能走,走过一个点可以获得该点上面的数字值,问最大能获得多少

思路:由于有环先强连通缩点,然后问题转化为dag,直接dp即可

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <stack>
using namespace std;

const int N = 1605;
const int d[2][2] = {0, 1, 1, 0};

int t, n, m, val[N];
char str[45][45];
vector<int> g[N], scc[N];
stack<int> S;

int pre[N], dfn[N], dfs_clock, sccno[N], sccn, scc_val[N];

void dfs_scc(int u) {
	pre[u] = dfn[u] = ++dfs_clock;
	S.push(u);
	for (int i = 0; i < g[u].size(); i++) {
		int v = g[u][i];
		if (!pre[v]) {
			dfs_scc(v);
			dfn[u] = min(dfn[u], dfn[v]);
		} else if (!sccno[v]) dfn[u] = min(dfn[u], pre[v]);
	}
	if (dfn[u] == pre[u]) {
		sccn++;
		int sum = 0;
		while (1) {
			int x = S.top(); S.pop();
			sum += val[x];
			sccno[x] = sccn;
			if (u == x) break;
		}
		scc_val[sccn] = sum;
	}
}

void find_scc() {
	dfs_clock = sccn = 0;
	memset(pre, 0, sizeof(pre));
	memset(sccno, 0, sizeof(sccno));
	for (int i = 0; i < n * m; i++)
		if (!pre[i]) dfs_scc(i);
}

int dp[N];

int dfs(int u) {
	if (dp[u] != -1) return dp[u];
	dp[u] = 0;
	for (int i = 0; i < scc[u].size(); i++) {
		int v = scc[u][i];
		dp[u] = max(dp[u], dfs(v));
	}
	dp[u] += scc_val[u];
	return dp[u];
}

int main() {
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &n, &m);
		for (int i = 0; i < n * m; i++) g[i].clear();
		for (int i = 0; i < n; i++)
			scanf("%s", str[i]);
		memset(val, 0, sizeof(val));
		int a, b;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (str[i][j] == '#') continue;
				if (str[i][j] >= '0' && str[i][j] <= '9') val[i * m + j] = str[i][j] - '0';
				if (str[i][j] == '*') {
					scanf("%d%d", &a, &b);
					g[i * m + j].push_back(a * m + b);
				}
				for (int k = 0; k < 2; k++) {
					int x = i + d[k][0];
					int y = j + d[k][1];
					if (x < 0 || x >= n || y < 0 || y >= m || str[x][y] == '#') continue;
					g[i * m + j].push_back(x * m + y);
				}
			}
		}
		find_scc();
		for (int i = 1; i <= sccn; i++) scc[i].clear();
		for (int u = 0; u < n * m; u++) {
			for (int j = 0; j < g[u].size(); j++) {
				int v = g[u][j];
				if (sccno[u] == sccno[v]) continue;
				scc[sccno[u]].push_back(sccno[v]);
			}
		}
		memset(dp, -1, sizeof(dp));
		printf("%d\n", dfs(sccno[0]));
	}
	return 0;
}
时间: 2024-08-05 15:08:41

POJ 3592 Instantaneous Transference(强连通+DP)的相关文章

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(建图强连通+单源最长路)

题目大意:有一张n*m的地图,每个点上可能是数字,代表矿石的数目,可能是*,表示一个传送阵,送往某个坐标,可能是#,代表不通.每次矿车只能往右方或者下方走一格,问从(0,0)点出发可以最多收集到多少矿石 思路:先根据矿车的可移动的方向建有向图,"*"导致可能会有环,所以先缩点变成有向无环图. 然后就是DAG上的最长路问题(拓扑排序+dp) 而且也是单源最长路问题,可以用最短路算法去做 吐槽一下debug了一天,原来是tarjan的时间戳写跪了,关键是直到现在仍不觉得那种写法是错的,对拍

POJ 3592 Instantaneous Transference Tarjan+SPFA

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

POJ3592 Instantaneous Transference 强连通+最长路

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

【连通图|强连通分量+最长路】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 1692 Crossed Matchings(DP)

Description There are two rows of positive integer numbers. We can draw one line segment between any two equal numbers, with values r, if one of them is located in the first row and the other one is located in the second row. We call this line segmen

POJ 3356 AGTC 最短编辑距离 DP

http://poj.org/problem?id=3356 题意: 给两个长度不大于1000的串,修改其中一个串使得两串相同,问最少修改次数.修改有三种,插入一个字符,删除一个字符,改变一个字符. 分析: 直接给方程. dp[i][j]表示第一个串前i位和第二串前j位匹配的最小修改次数. dp[0][0] = 0, dp[length(x)][length(y)]为答案. dp[i][j] = min(dp[i-1][j-1] + x[i] != y[j], dp[i-1][j] + 1, d

POJ 3666 Making the Grade [DP]

题意: 给定一个序列,以最小代价将其变成单调不增或单调不减序列,这里的代价看题目公式. 思路: 很容易想到是DP. 1. 对前i个序列,构成的最优解其实就是与两个参数有关.一个是这个序列处理后的最大值mx,和这个序列处理的代价值cost. 显然最大值mx最小最好(这样第i+1个值可以不花代价直接接在其后面的可能性更大),cost最小也最好(题意要求),但是两者往往是鱼和熊掌. 用dp[i][j]表示:前i个数构成的序列,这个序列最大值为j,dp[i][j]的值代表相应的cost. 所以状态转移方

poj 2081 Recaman&#39;s Sequence (dp)

Recaman's Sequence Time Limit: 3000MS   Memory Limit: 60000K Total Submissions: 22566   Accepted: 9697 Description The Recaman's sequence is defined by a0 = 0 ; for m > 0, am = am−1 − m if the rsulting am is positive and not already in the sequence,