首页 > 代码库 > POJ 3592 Instantaneous Transference Tarjan+SPFA

POJ 3592 Instantaneous Transference Tarjan+SPFA

题目大意:给出一张地图,有数字的点代表上面有数字个矿物,*代表这个点可以传送到另一个点上,#代表不能走。从一个点只能到这个点的下方和右方。现在从(0,0)开始,问最多可以收集多少矿物。


思路:这个题肯定是建图,然后最长路,关键是有了传送,就有可能形成正权环,然后在SPFA的过程中就会死循环。一个环上的所有权值只能得到一次,所以就用一次Tarjan求出所有的环,把权值累计一下,变成一个点,然后重新建图。这样得到的图就是拓扑图了,没有环,可以无忧无虑的SPFA了。

PS:这个题我用拓扑排序怎么也切不了,求大神告知这是为什么!!!


CODE:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 20010
using namespace std;

int cases;
int m,n;
char src[50][50];
int transmit[MAX],points;

int head[MAX],total;
int next[MAX],aim[MAX];

int dfn[MAX],low[MAX],_clock;
int stack[MAX],top;
bool in_stack[MAX];
int changed[MAX],scc,val[MAX];
int a[MAX];

int _head[MAX],_total;
int _next[MAX],_aim[MAX];

int f[MAX];
bool v[MAX];

inline void Initialize()
{
	total = _total = _clock = top = points = scc = 0;
	memset(head,0,sizeof(head));
	memset(_head,0,sizeof(_head));
	memset(dfn,0,sizeof(dfn));
	memset(in_stack,false,sizeof(in_stack));
	memset(val,0,sizeof(val));
}

inline void Add(int x,int y)
{
	next[++total] = head[x];
	aim[total] = y;
	head[x] = total;
}

inline void _Add(int x,int y)
{
	_next[++_total] = _head[x];
	_aim[_total] = y;
	_head[x] = _total;
}

void Tarjan(int x)
{
	dfn[x] = low[x] = ++_clock;
	in_stack[x] = true;
	stack[++top] = x;
	for(int i = head[x]; i; i = next[i]) {
		if(!dfn[aim[i]])
			Tarjan(aim[i]),low[x] = min(low[x],low[aim[i]]);
		else if(in_stack[aim[i]])
			low[x] = min(low[x],dfn[aim[i]]);
	}
	if(dfn[x] == low[x]) {
		scc++;
		int temp;
		do {
			temp = stack[top--];
			changed[temp] = scc;
			in_stack[temp] = false;
			val[scc] += a[temp];
		}while(temp != x);
	}
}

inline void SPFA()
{
	static queue<int> q;
	while(!q.empty()) 	q.pop();
	memset(f,0,sizeof(f));
	memset(v,false,sizeof(v));
	f[changed[0]] = val[changed[0]];
	q.push(changed[0]);
	while(!q.empty()) {
		int x = q.front(); q.pop();
		v[x] = false;
		for(int i = _head[x]; i; i = _next[i])
			if(f[_aim[i]] < f[x] + val[_aim[i]]) {
				f[_aim[i]] = f[x] + val[_aim[i]];
				if(!v[_aim[i]]) {
					v[_aim[i]] = true;
					q.push(_aim[i]);
				}
			}
	}
}

int main()
{
	for(cin >> cases; cases; --cases) {
		scanf("%d%d",&n,&m);
		Initialize();
		for(int i = 0; i < n; ++i)
			scanf("%s",src[i]);
		for(int i = 0; i < n; ++i)
			for(int x,y,j = 0;j < m; ++j)
				if(src[i][j] == '*') {
					scanf("%d%d",&x,&y);
					a[i * m + j] = 0;
					if(src[x][y] != '#')
						Add(i * m + j,x * m + y);
					if(i + 1 < n && src[i + 1][j] != '#')
						Add(i * m + j,(i + 1) * m + j);
					if(j + 1 < m && src[i][j + 1] != '#')
						Add(i * m + j,i * m + j + 1);
				}
				else if(src[i][j] != '#') {
					a[i * m + j] = src[i][j] - '0';
					if(i + 1 < n && src[i + 1][j] != '#')
						Add(i * m + j,(i + 1) * m + j);
					if(j + 1 < m && src[i][j + 1] != '#')
						Add(i * m + j,i * m + j + 1);
				}
		for(int i = 0; i < m * n; ++i)
			if(!dfn[i])	Tarjan(i);
		for(int x = 0; x < m * n; ++x)
			for(int i = head[x]; i; i = next[i])
				if(changed[x] != changed[aim[i]])
					_Add(changed[x],changed[aim[i]]);
		SPFA();
		int *ans = max_element(f + 1,f + scc + 1);
		printf("%d\n",*ans);
	}
	return 0;
}


POJ 3592 Instantaneous Transference Tarjan+SPFA