关闭

POJ3592 Instantaneous Transference 强连通+最长路

标签: c++
695人阅读 评论(0) 收藏 举报
分类:

题目链接:

poj3592



题意:

给出一幅n X m的二维地图,每个格子可能是矿区,障碍,或者传送点 用不同的字符表示;

有一辆矿车从地图的左上角(0,0)出发,只能往右走或往下走,或者通过传送点  选择是否 传送到特定地点

采过的矿的格子 矿会消失;问这辆矿车最多能采多少矿



解题思路:

首先重新建图,将图中二维的顶点压缩成一维的顶点             (方便Tarjan算法)

每个顶点往右,下的顶点建边,传送点的格子往特定顶点建边(建边的两端不能有障碍)

得到一幅可能存在环的有向图;

因为采过矿的格子不可以二次采矿,所以经过某个环等于采集了整个环中所有的矿

我们用Tarjan算法缩点 再重新建图

得到一幅无环有向图,而图中每条边(u->v)的权值应等于value[v]

最后再用spfa求这幅图的最长路即可



代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 1650
using namespace std;
struct node
{
    int to,next,w;
} edge1[maxn*3],edge2[maxn*3];
int head1[maxn],head2[maxn];
int s1,s2;

int dfn[maxn], low[maxn],num;

int sta[maxn],insta[maxn], top;

int belong[maxn],block;

int n,m,ss,v1[maxn],v2[maxn];
char map[45][45];

void init()
{
    memset(head1,-1,sizeof(head1));
    memset(head2,-1,sizeof(head2));
    memset(dfn,0,sizeof(dfn));
    memset(insta,0,sizeof(insta));
    memset(belong,0,sizeof(belong));
    memset(v2,0,sizeof(v2));
    s1=s2=num=top=block=0;
}

int judge(int x,int y)
{
    if(x<0||y<0||x>=n||y>=m)
        return -1;
    if(map[x][y]>='0'&&map[x][y]<='9')
        return 1;
    if(map[x][y]=='*')
        return 2;
    if(map[x][y]=='#')
        return -1;
}

void addedge(int d,int u,int v,int w)
{
    if(d==1){
        edge1[s1]={v,head1[u]};
        head1[u]=s1++;
    }
    else {
        edge2[s2]={v,head2[u],w};
        head2[u]=s2++;
    }
}

void Tarjan(int u,int pre)
{
    dfn[u]=low[u]=++num;
    insta[u]=1;
    sta[top++]=u;
    for(int i=head1[u];i!=-1;i=edge1[i].next)
    {
        int v=edge1[i].to;
        if(!dfn[v])
        {
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(insta[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])           //缩点
    {
        block++;
        int d=-1;
        while(d!=u)
        {
            d=sta[--top];
            insta[d]=0;
            belong[d]=block;
            v2[block]+=v1[d];
        }
    }
}

void rebuild()
{
    int u,v;
    for(int i=0;i<n*m;i++)
    {
        u=belong[i];
        for(int j=head1[i];j!=-1;j=edge1[j].next)
        {
            v=edge1[j].to;
            v=belong[v];
            if(u!=v)              //重新建边
                addedge(2,u,v,v2[v]);
        }
    }
}

void spfa()
{
    int u,v,start=belong[0];   //起点为(0,0)所在的强连通分量里面
    queue<int>q;
    int vis[maxn]={0};
    int dis[maxn]={0};
    vis[start]=1;
    dis[start]=v2[start];
    q.push(start);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head2[u];i!=-1;i=edge2[i].next)
        {
            v=edge2[i].to;
            if(dis[v]<dis[u]+edge2[i].w)
            {
                dis[v]=dis[u]+edge2[i].w;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    int ans=0;
    for(int i=1;i<=block;i++)
        if(dis[i]>ans)
            ans=dis[i];
    cout<<ans<<endl;

}

int main()
{
    int T,s,ss,loc;
    char ch;
    int pos[maxn][2];
    scanf("%d",&T);
    while(T--)
    {
        s=1,ss=0;
        init();
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
            {
                cin>>map[i][j];
                if(map[i][j]=='*')
                    ss++;
            }
        for(int i=1; i<=ss; i++)                //记录第i个传送点的传送位置
            scanf("%d%d",&pos[i][0],&pos[i][1]);

        for(int i=0; i<n; i++)
            for(int j=0; j<m; j++)
            {
                loc=i*m+j;                            //一维顶点
                if(judge(i,j)==1)
                    v1[loc]=map[i][j]-'0';
                else if(judge(i,j)==2)
                    v1[loc]=0;                         //传送点没有矿
                if(judge(i,j)!=-1)
                {
                    if(judge(i+1,j)!=-1)               //下
                        addedge(1,loc,loc+m,0);
                    if(judge(i,j+1)!=-1)               //右
                        addedge(1,loc,loc+1,0);
                    if(judge(i,j)==2)                  //传送点
                        addedge(1,loc,pos[s][0]*m+pos[s++][1],0);
                }
                else
                    v1[loc]=-1;       //障碍
            }

        for(int i=0;i<n*m;i++)
            if(!dfn[i]&&v1[i]!=-1)          //注意障碍不能进行Tarjan
                Tarjan(i,-1);
        rebuild();
        spfa();
    }
    return 0;
}



0
0
查看评论

Instantaneous Transference poj3592(【强连通分量】【最长路】)

Instantaneous Transference Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 6577   Accepted:...
  • SDUTyangkun
  • SDUTyangkun
  • 2017-01-14 17:00
  • 141

POJ3592 Instantaneous Transference【强连通分量】【最长路】

题目大意: 有一个N*M的矩阵地图,矩阵中用了多种字符代表不同的地形,如果是数字X(0~9),则表示 该区域为矿区,有X单位的矿产。如果是"*",则表示该区域为传送点,并且对应唯一一个目标 坐标。如果是"#",,则表示该区域为山区,矿车不能进入。现在矿车的出发...
  • u011676797
  • u011676797
  • 2015-02-11 20:46
  • 1449

【POJ】3592 Instantaneous Transference 强连通+最长路

Instantaneous Transference Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 5581 Accepted: 1237 Description...
  • u013368721
  • u013368721
  • 2014-07-09 18:51
  • 724

POJ3592 Instantaneous Transference题解

题意:   给一个矩形,矩形中某些点有一定数量的矿石,有些点为传送点,有些点为障碍。你驾驶采矿车(ore-miner truck,我也不知道是什么),从左上角出发,采尽量多的矿石,矿石不可再生。不能往左边或者上面走。传送点可以往左边或上面传。2 分析:   可以把矩形看作一张图,每个格子为...
  • hehephper
  • hehephper
  • 2017-01-31 10:43
  • 94

【强连通缩点+最长路】Instantaneous Transference

Instantaneous Transference Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3722   Accepted: 788 De...
  • wu_yihao
  • wu_yihao
  • 2012-03-29 08:28
  • 710

poj 3592 Instantaneous Transference 强连通+缩点+最长路

题目链接:http://poj.org/problem?id=3592 题目大意 :坦克一开始在(0,0),只可以向右边或下边走,走过的时候可以获得该格子上面的矿物(只能采集一次,之后矿物消失)。 同时地图上存在若干神奇的传送门,若走到上面,可以选择 是否传送,如果传送,那么传送目标的坐标诶出,...
  • xiaotaike1
  • xiaotaike1
  • 2013-08-09 21:40
  • 339

poj 3592 Instantaneous Transference(强连通+最长路)

Instantaneous Transference Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5076   Accepted: 1103 Des...
  • WEYuLi
  • WEYuLi
  • 2013-08-16 20:07
  • 552

POJ 3592 Instantaneous Transference强连通加缩点后求最长路

n*m的地图,从0,0,开始走,只能向下或向右走,每一个坐标只有0~9、#、*。如果为#代表墙不能通过,如果为*代表是传送门,可以传达其他位置,如果为数字,则代表该点的价值。求最大价值。 先输入T,T组数据。 输入n、m代表地图的大小。然后输入地图,接下来输入每一个传送门能传送的位置坐标。 先...
  • ACMer_AK
  • ACMer_AK
  • 2016-08-12 21:07
  • 108

poj3592 Instantaneous Transference tarjan缩点+建图

//给一个n*m的地图,坦克从(0 , 0)开始走 //#表示墙不能走,*表示传送门可以传送到指定地方,可以选择也可以选择不传送 //数字表示该格的矿石数, //坦克从(0,0)开始走,只能往右和往下走, //问最多能得到多少矿石 //直接建图,但由于有传送门,需要缩点 //然后用dfs直接搜一条权...
  • cq_pf
  • cq_pf
  • 2015-08-10 09:38
  • 471

poj 3592 Instantaneous Transference(tarjan + 缩点 + 最长路)

http://poj.org/problem?id=3592 题意:给定一个n*m格子的有向图,每个格子上是数字,‘#’或 '*' ,数字代表该格子上的矿石数目,'#'代表该格子不能走,' * '代表一个传送阵,送往某个给定的坐标。每次矿车只能向下或...
  • u013081425
  • u013081425
  • 2014-01-18 15:30
  • 1005