题意:一辆坦克从N*M矩阵的左上角出发,每次往右或往下走一格,每格可以是'#'(表示不可以走),'*'表示传送门,或者是数字,表示在该格可以获得的值(只能取一次),传送门可以将到达该处的坦克传送到指定位置,你可以选择被传送或者走相邻的格,问坦克可以获得的值的和最大为多少。
思路:N*M矩阵上每个点看成图中的一个点,能够走的连边。那么显然在一个强连通分量里的点的值是全部能够得到的。那么思路就是先求强连通分量,然后缩点(此时点上的权值是原图所包含点得权值之和)。进而求一条从左上角点所在强连通分量出发的最长路。可以用spfa来求,也可以用dp的思想,做dp的时候对点的处理顺序蕴含了拓扑排序的思想。
写dp的时候wa了很多次,是在建新图时的入度数组写错了。有重边时在新图中也只有一条边,所以d数组也只增加1,需要注意。。
版本1:dp
#include
#include
#include
#include
#include
#include
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
#define N 42
char s[N][N];
int T,n,m,w[N*N],t[N*N],res;//w是原始价值,t是缩点后的价值
struct edge{
int y,next;
}e[N*N*3];
int first[N*N],top;
int strong[N*N],dfn[N*N],low[N*N],stack[N*N],inst[N*N],con,idx,ts;
int id(int x,int y){
return x*m+y;
}
int g[N*N][N*N],d[N*N],dp[N*N];
void init(){
clc(first, -1);
clc(dfn, -1);
clc(inst, 0);
clc(t,0);
clc(g, 0);
clc(strong, 0);
clc(d, 0);
clc(dp, 0);
clc(w,0);
top = con = idx = ts = res = 0;
}
void add(int x,int y){
e[top].y = y;
e[top].next = first[x];
first[x] = top++;
}
void tarjan(int x){
dfn[x] = low[x] = ++idx;
stack[ts++] = x;
inst[x] = 1;
for(int i = first[x];i!=-1;i=e[i].next){
if(dfn[e[i].y] == -1){
tarjan(e[i].y);
low[x] = min(low[x],low[e[i].y]);
}else if(inst[e[i].y])
low[x] = min(low[x],dfn[e[i].y]);
}
if(dfn[x] == low[x]){
con++;
do{
strong[stack[--ts]] = con;
inst[stack[ts]] = 0;
t[con] += w[stack[ts]];
}while(x != stack[ts]);
}
}
int main(){
scanf("%d",&T);
while (T--) {
int i,j,a,b,now;
init();
scanf("%d %d",&n,&m);
//clc(s,'#');
for(i = 0;i q;
q.push(strong[0]);
dp[strong[0]] = t[strong[0]];
while(!q.empty()){
now = q.front();
q.pop();
for(i = 1;i<=con;i++){
if(g[now][i] && d[i]>=1){
dp[i] = max(dp[i],dp[now]+t[i]);
d[i]--;
if(!d[i])
q.push(i);
}
}
}
for(i = 1;i<=con;i++)
res = max(res,dp[i]);
printf("%d\n",res);
}
return 0;
}
#include
#include
#include
#include
#include
#include
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
#define N 42
char s[N][N];
int T,n,m,w[N*N],t[N*N],res;//w是原始价值,t是缩点后的价值
struct edge{
int y,next;
}e[N*N*3];
int first[N*N],top;
int strong[N*N],dfn[N*N],low[N*N],stack[N*N],inst[N*N],con,idx,ts;
int id(int x,int y){
return x*m+y;
}
struct ee{
int y,w,next;
}e2[N*N*3];
int f2[N*N],top2,dis[N*N];
void init(){
clc(first, -1);
clc(dfn, -1);
clc(inst, 0);
clc(t,0);
clc(strong, 0);
clc(w,0);
top = con = idx = ts = res = 0;
}
void add(int x,int y){
e[top].y = y;
e[top].next = first[x];
first[x] = top++;
}
void tarjan(int x){
dfn[x] = low[x] = ++idx;
stack[ts++] = x;
inst[x] = 1;
for(int i = first[x];i!=-1;i=e[i].next){
if(dfn[e[i].y] == -1){
tarjan(e[i].y);
low[x] = min(low[x],low[e[i].y]);
}else if(inst[e[i].y])
low[x] = min(low[x],dfn[e[i].y]);
}
if(dfn[x] == low[x]){
con++;
do{
strong[stack[--ts]] = con;
inst[stack[ts]] = 0;
t[con] += w[stack[ts]];
}while(x != stack[ts]);
}
}
void add2(int x,int y,int w){
e2[top2].y = y;
e2[top2].w = w;
e2[top2].next = f2[x];
f2[x] = top2++;
}
int relax(int x,int y,int w){
if(dis[x]+w > dis[y]){
dis[y] = dis[x]+w;
return 1;
}
return 0;
}
void spfa(int s){
int i,now;
int used[N*N]
;
clc(dis,0);
dis[s] = t[s];
clc(used,0);
used[s] = 1;
queue q;
q.push(s);
while(!q.empty()){
now = q.front();
q.pop();
used[now] = 0;
for(i = f2[now];i!=-1;i=e2[i].next)
if(relax(now,e2[i].y,e2[i].w) && !used[e2[i].y]){
used[e2[i].y] = 1;
q.push(e2[i].y);
}
}
}
int main(){
scanf("%d",&T);
while (T--) {
int i,j,a,b;
init();
scanf("%d %d",&n,&m);
for(i = 0;i