[来源未知]传送

内存256M,时限2s
传送
【问题描述】
现在这里有一处矿区,而你正操控着一个采矿车。你的任务是在这个矿区获取最多的矿石。这个矿区是一个由n*m个小格子组成的矩形区域,其中一些格子有矿石,而另一些没有。矿石只能被采集一遍,而不会重新产生。
矿车的初始位置为该矩形地区的西北角。它只能向东或向南的临近的格子移动,而不能向北或向西移动。一些格子有传送门而使矿车可以通过超时空传送到达某个特定的格子。
现在,因为你是这个矿车的指挥,所以你要来决定是否使用传送门(可以选择留在原地)。而这种传送门是永远不会消失的,当你到达有这种传送门的格子时,就可以立刻使用它。
【输入数据】
输入的第一行为一个整数T(1<=T<=5),表示数据的组数。
对于每一组数据,第一行是两个由空格隔开的整数N和M(2<=N,M<=40)。
接下来的N行每行将是一个包含M个字符的字符串。
每一个字符可以是一个整数X(0<=X<=9)或一个“*”或一个“#”。
如果是一个整数X表示这个格子有X单位的矿石,当你的矿车经过这里时可以把它们全部采集走。
如果是“*”则表示在这个格子有一个传送门。
如果是“#”则表示在这个格子里是有障碍物而不能到达的。
矿车的起始位置一定没有障碍物。
就上面的地图显示的,地图中一共有K个“*”。接下来的K行描述每个传送门传送的目的地,按照传送门的位置从北到南,从西到东的顺序给出(即逐行给出)。(传送门的目的地的横纵坐标是从0到N-1,0到M-1的)
【输出数据】
对于每一组数据,你应该输出你最多能够获得多少单位的矿石。
【输入样例】
1
2 2
11
1*
0 0
【输出样例】
3
【Hint】
你的终点是任意的,你不能走到地图外,传送门是不会把你传送到地图外的。

为什么这道sb题我不会做啊….gg稳了

sol:
发现原本是DAG,有传送门有环,tarjan一下。

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
const int N=50;
const int M=10000;
const int dx[]={1,0};
const int dy[]={0,1};
int n,m,Time,ID,tot,Num;
int dfn[M],low[M],sta[M],id[M],val[M];
int nex[M],go[M],fir[M],dis[M]; 
bool vis[M];
int point[M],num[N][N];
char sr[N][N];
inline int read()
{
    char c;
    int res,flag=0;
    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
    res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
    return flag?-res:res;
}
inline void add(int x,int y)
{
    nex[++tot]=fir[x];fir[x]=tot;go[tot]=y;
}
inline void tarjan(int u)
{
    vis[u]=1;
    dfn[u]=low[u]=++Time;
    sta[++sta[0]]=u;
    int e,v;
    for(e=fir[u];v=go[e],e;e=nex[e])
    if(!dfn[v])
    {
        tarjan(v);
        low[u]=min(low[u],low[v]);
    }
    else if(vis[v]) low[u]=min(low[u],dfn[v]);
    if(low[u]==dfn[u])
    {
        ++ID;
        do
        {
            v=sta[sta[0]--];
            vis[v]=0;
            id[v]=ID;
            val[ID+Num]+=point[v];
        }while(v!=u);
    }
}
struct cc
{
    int x,y;
}q[M];
int h[M],top;
inline void solve()
{
    n=read();
    m=read();
    tot=Time=top=Num=0;
    memset(id,0,sizeof(id));
    memset(val,0,sizeof(val));
    memset(fir,0,sizeof(fir));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    int u,v,e,ans=0;
    for(int i=0;i<n;++i)
    {
        scanf("%s",sr[i]);
        for(int j=0;j<m;++j)
        {
            num[i][j]=++Num;
            if(sr[i][j]=='*')
            {
                ++top;
                q[top].x=i;
                q[top].y=j;
                point[Num]=0;
            }
            else if(sr[i][j]!='#')
            point[Num]=sr[i][j]-'0';
            else point[Num]=0;
        }
    }
    int x,y;
    for(int i=1;i<=top;++i)
    {
        x=read();
        y=read();
        if(sr[x][y]=='#') continue;
        add(num[q[i].x][q[i].y],num[x][y]);
    }
    for(int i=0;i<n;++i)
    for(int j=0;j<m;++j)
    if(sr[i][j]!='#')
    {
        for(e=0;e<=1;++e)
        {
            x=i+dx[e];
            y=j+dy[e];
            if(x>=0&&x<n&&y>=0&&y<m&&sr[x][y]!='#')
            add(num[i][j],num[x][y]);
        }
    }
    for(int i=0;i<n;++i)
    for(int j=0;j<m;++j)
    if(!id[num[i][j]]) tarjan(num[i][j]);

    for(u=1;u<=Num;++u)
    for(e=fir[u];v=go[e],e;e=nex[e])
        if(id[u]!=id[v]) add(Num+id[u],Num+id[v]);

    for(int i=1;i<=ID;++i) dis[i+Num]=-1;;

    int t=0,w=1;
    h[1]=id[1]+Num;
    dis[id[1]+Num]=val[id[1]+Num];
    while(t<w)
    {
        u=h[++t];
        for(e=fir[u];v=go[e],e;e=nex[e])
        if(dis[v]<dis[u]+val[v])
        {
            dis[v]=dis[u]+val[v];
            if(!vis[v])
            {
                vis[v]=1;
                h[++w]=v;
            }
        }
        vis[u]=0;
    }
    for(int i=1;i<=ID;++i)
    ans=max(ans,dis[i+Num]);
    printf("%d\n",ans);
}
int main()
{
    freopen("tramcar.in","r",stdin);
    freopen("tramcar.out","w",stdout);
    int T=read();
    while(T--)
    solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值