Poj 3592 Instantaneous Transference【强连通Tarjan+染色缩点+SPFA】

来源:互联网 发布:php获取js变量的方法 编辑:程序博客网 时间:2024/04/28 00:49

Instantaneous Transference

Time Limit: 5000MS

 

Memory Limit: 65536K

Total Submissions: 6367

 

Accepted: 1439

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 function, it will be transferred to the specified point immediately, regardless of how far it is.

Now there is a mining area, and you are driving an ore-miner truck. Your mission is to take the maximum ores in the field.

The ore area is a rectangle region which is composed by n × m small squares, some of the squares have numbers of ores, while some do not. The ores can't be regenerated after taken.

The starting position of the ore-miner truck is the northwest corner of the field. It must move to the eastern or southern adjacent square, while it can not move to the northern or western adjacent square. And some squares have magic power that can instantaneously transfer the truck to a certain square specified. However, as the captain of the ore-miner truck, you can decide whether to use this magic power or to stay still. One magic power square will never lose its magic power; you can use the magic power whenever you get there.

Input

The first line of the input is an integer T which indicates the number of test cases.

For each of the test case, the first will be two integers NM (2 ≤ NM ≤ 40).

The next N lines will describe the map of the mine field. Each of the N lines will be a string that contains M characters. Each character will be an integer X (0 ≤ X ≤ 9) or a '*' or a '#'. The integer X indicates that square hasX units of ores, which your truck could get them all. The '*' indicates this square has a magic power which can transfer truck within an instant. The '#' indicates this square is full of rock and the truck can't move on this square. You can assume that the starting position of the truck will never be a '#' square.

As the map indicates, there are K '*' on the map. Then there follows K lines after the map. The next K lines describe the specified target coordinates for the squares with '*', in the order from north to south then west to east. (the original point is the northwest corner, the coordinate is formatted as north-south, west-east, all from 0 to N - 1,- 1).

Output

For each test case output the maximum units of ores you can take.

Sample Input

1

2 2

11

1*

0 0

Sample Output

3

Source

South Central China 2008 hosted by NUDT


题目大意:

有t组数据,对于每组数据有一个n*m的图。其中有三种字符:

1、0-9的数字,表示矿石的数量。

2、*表示传送阵(图里边一共有k个传送阵),有特定能够传送的位子,其位子在图后边跟着K行,每一行一个坐标,表示第几个出现的传送阵固定能够到达的地点。

3、#表示不能走的地点。

问:从左上角出发,到任意点作为终点,只能向下向右走(当然传送阵除外),一个点的矿石只能拿一次,求一条有向路使得整个路径中拿取的矿石数量最大。


分析:首先我们分析要使用的算法,如果我们Bfs的话,因为传送阵是可以多次使用的,而且可能每次使用都能带来更多矿石的收益,所以想直接Bfs,没法判断一个点到底走多少次为最大限制,简单点说也就是有环存在不好处理,所以我们定性思路到图上。


思路:

1、首先我们将图的节点进行编号,左上角的格子我们标号为节点1,然后对于样例图来讲,我们就能够编号为这样:

1 23 4

然后对于走的方式:只能向右和向下,对于每个点都建能够到达的点一条有向边,其样例的建边信息:

1 21 32 43 44 1//传送阵的特定点

2、然后我们发现,因为传送阵的存在,我们不得不去处理有向环的问题,这里我们也就不难想到用Kosaraju算法或者是Tarjan之类的求强连通分量的算法来染色缩点。我们的实现用Tarjan来搞定。


3、缩点之后图就一定会变成一个DAG图,而且每个点的点权值就是其强连通分量中所有矿石的价值和。然后我们从节点1所在的缩点进行一遍SPFA求最长路,辣么:
output=max(output【i】)【0<=i<=sig】


AC代码:

#include<stdio.h>#include<string.h>#include<vector>#include<queue>using namespace std;#define maxn 1000000vector<int >mp[maxn];vector<int >mp2[maxn];int dis[maxn];int ans[maxn];int degree[maxn];int color[maxn];int stack[maxn];int vis[maxn];int dfn[maxn];int low[maxn];int val[maxn];char a[50][50];int fx[2]={1,0};int fy[2]={0,1};int tt,cnt,sig,nn,mm;void init(){    memset(val,0,sizeof(val));    memset(degree,0,sizeof(degree));    memset(color,0,sizeof(color));    memset(stack,0,sizeof(stack));    memset(low,0,sizeof(low));    memset(dfn,0,sizeof(dfn));    memset(vis,0,sizeof(vis));}void SPFA(int ss,int n){    memset(vis,0,sizeof(vis));    for(int i=1;i<=n;i++)dis[i]=0;    dis[ss]=val[ss];    vis[ss]=1;    queue<int >s;    s.push(ss);    while(!s.empty())    {        int u=s.front();        s.pop();vis[u]=0;        for(int i=0;i<mp2[u].size();i++)        {            int v=mp2[u][i];            if(dis[v]<dis[u]+val[v])            {                dis[v]=dis[u]+val[v];                if(vis[v]==0)                {                    vis[v]=1;                    s.push(v);                }            }        }    }    int output=0;    for(int i=1;i<=n;i++)    {        output=max(output,dis[i]);    }    printf("%d\n",output);}void Tarjan(int u){    vis[u]=1;    stack[++tt]=u;    low[u]=dfn[u]=cnt++;    for(int i=0;i<mp[u].size();i++)    {        int v=mp[u][i];        if(vis[v]==0)Tarjan(v);        if(vis[v]==1)low[u]=min(low[u],low[v]);    }    if(dfn[u]==low[u])    {        sig++;        do        {            color[stack[tt]]=sig;            vis[stack[tt]]=-1;        }        while(stack[tt--]!=u);    }}void Slove(int n){    sig=0;cnt=1;tt=-1;    memset(vis,0,sizeof(vis));    for(int i=1;i<=n;i++)    {        if(vis[i]==0)        Tarjan(i);    }    int x=1,y=1;    for(int i=1;i<=n;i++)    {        int tmp=a[x][y]-'0';        y++;        if(y>mm)y=1,x++;        val[color[i]]+=tmp;    }    for(int i=1;i<=n;i++)    {        for(int j=0;j<mp[i].size();j++)        {            if(color[i]!=color[mp[i][j]])            {                mp2[color[i]].push_back(color[mp[i][j]]);            }        }    }    SPFA(color[1],sig);}int main(){    int t;    scanf("%d",&t);    while(t--)    {        int n,m;        init();        scanf("%d%d",&n,&m);        nn=n;mm=m;        for(int i=1;i<=n*m;i++)mp2[i].clear(),mp[i].clear();        for(int i=1;i<=n;i++)        {            scanf("%s",a[i]+1);        }        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                if(a[i][j]=='#')continue;                for(int k=0;k<2;k++)                {                    int xx=i+fx[k];                    int yy=j+fy[k];                    if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&a[xx][yy]!='#')                    {                        mp[(i-1)*m+j].push_back((xx-1)*m+yy);                    }                }                if(a[i][j]=='*')                {                    int x,y;                    scanf("%d%d",&x,&y);                    x++;y++;                    mp[(i-1)*m+j].push_back((x-1)*m+y);                    a[i][j]='0';                }            }        }        Slove(n*m);    }}




0 0
原创粉丝点击