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;
}

 

posted @ 2013-05-24 09:29  Titanium  阅读(395)  评论(0编辑  收藏  举报