poj2592 Instantaneous Transference

来源:互联网 发布:韩信点兵算法提纲 编辑:程序博客网 时间:2024/06/08 14:57

Instantaneous Transference
Time Limit: 5000MS Memory Limit: 65536KTotal Submissions: 6558 Accepted: 1482

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 has X 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

12 2111*0 0

Sample Output

3

大意:

给你一张图,矿车在左上角的点,然后矿车只能向右或者向下走。

其中图上

1.数字表示当前点的矿的数量。

2.*表示可以进行超时空移动的点,它能移动的位置,在输入中会告诉。

3.#表示当前点矿车是不能走的,也就是说这个点完全排除在外的。

之后就是问你能采到的最大矿值了。

如果我们把图上的每个点按照能走的规则连接上一条边的话,不难发现就是求一个从左上角的点到别的所有点的一个最大值。

如果给每个点加一个边权的话,就是求一个最长路咯。

这里因为是强连通的题嘛,一开始就是想到先求出强连通分量,然后缩点,然后再求一个最长路,这样肯定是没问题的。

后来想了一想不缩点也能过吧,只不过这里要注意一点就是吃完了矿的,边权要相应的变为0。这样更新完了之后,也是可以的。

当然博主表示懒得试了,准备开下一个题了,有兴趣的可以自己试一下咯。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <stack>using namespace std;const int MAXN=1600+10;int n,m;int point;char tu[45][45];int xing[MAXN];int num[MAXN][MAXN];//给点表号,要直接除去‘#’int dfn[MAXN],sccno[MAXN],dfs_clock,scc_cnt;int sum[MAXN],cost[MAXN];typedef vector<int>ve;vector<ve>G(MAXN),G2(MAXN);stack<int>S;int dfs(int u){    int lowu=dfn[u]=++dfs_clock;    S.push(u);    for(int i=0,l=G[u].size(); i<l; ++i)    {        int v=G[u][i];        if(!dfn[v])        {            int lowv=dfs(v);            lowu=min(lowu,lowv);        }        else if(!sccno[v])        {            lowu=min(lowu,dfn[v]);        }    }    if(lowu==dfn[u])    {        scc_cnt++;        while(1)        {            int x=S.top();            S.pop();            sum[scc_cnt]+=cost[x];            sccno[x]=scc_cnt;            if(x==u)break;        }    }    return lowu;}void find_scc(){    memset(sccno,0,sizeof(sccno));    memset(dfn,0,sizeof(dfn));    memset(sum,0,sizeof(sum));    dfs_clock=scc_cnt=0;    for(int i=0;i<point;++i)if(!dfn[i])dfs(i);}int vis[MAXN],dis[MAXN];void spfa(){    for(int i=1;i<=scc_cnt;++i)    {        dis[i]=-1;        vis[i]=0;    }    int q[MAXN];    int top=0;    q[top++]=sccno[0];    dis[sccno[0]]=sum[sccno[0]];    while(top)    {        int u=q[--top];        vis[u]=0;        for(int i=0,l=G2[u].size();i<l;++i)        {            int v=G2[u][i];            if(dis[u]+sum[v]>dis[v])            {                dis[v]=dis[u]+sum[v];                if(!vis[v])                {                    vis[v]=1;                    q[top++]=v;                }            }        }    }}int main(){    int i,j,l;    int ca;    scanf("%d",&ca);    while(ca--)    {        scanf("%d%d",&n,&m);        point=0;        int cnt=0;        memset(num,-1,sizeof(num));        memset(cost,0,sizeof(cost));        for(i=0; i<n; ++i)        {            scanf("%s",tu[i]);            for(j=0;j<m; ++j)            {                if(tu[i][j]!='#')                {                    num[i][j]=point++;                    if(tu[i][j]=='*')xing[cnt++]=num[i][j];                    else cost[num[i][j]]=tu[i][j]-'0';                }            }        }        for(i=0;i<point;++i)        {            G[i].clear();            G2[i].clear();        }        //加超时空移动的边        int hang,lie;        for(i=0; i<cnt; ++i)        {            scanf("%d%d",&hang,&lie);            if(tu[hang][lie]!='#')                G[xing[i]].push_back(num[hang][lie]);        }        //添加能向右下的边        for(i=0; i<n; ++i)            for(j=0; j<m; ++j)            {                if(tu[i][j]=='#')continue;                if(j+1<m&&tu[i][j+1]!='#')                {                    G[num[i][j]].push_back(num[i][j+1]);                }                if(i+1<n&&tu[i+1][j]!='#')                {                    G[num[i][j]].push_back(num[i+1][j]);                }            }            find_scc();        //缩点,建立新图,找最长路        for(i=0;i<point;++i)            for(j=0,l=G[i].size();j<l;++j)            {                int v=G[i][j];                if(sccno[i]!=sccno[v])                {                    G2[sccno[i]].push_back(sccno[v]);                }            }            spfa();            //找到那条最长的路记录下值            int ans=0;            for(i=1;i<=scc_cnt;++i)            {                ans=max(ans,dis[i]);            }            printf("%d\n",ans);    }    return 0;}






0 0
原创粉丝点击