poj 3592 强连通分量+最长路(spfa或者dp)(Instantaneous Transference)

题意:一辆坦克从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;
}

版本2:spfa

#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


你可能感兴趣的:(图论——强连通分量,割点,割边)