poj 3592 Instantaneous Transference

http://poj.org/problem?id=3592

每次做联通分量的题都是细节方面出错 伤不起呀

一张图 有些点是有矿可走 有些不可走 有些是时空转换点

矿车从左上开始走问最多能才多少矿

1,把二维图变成一维 由于时空转换点的存在使图存在了环

2,缩点 把环缩成一个点

3,重新建树,

4,搜索最多矿

以后再也不在Tarjan里进行重建图了 太容易出错了

果断在Tarjan后再dfs重新建图 虽然效率低了点但是不容易出错

而且只要整体算法选择正确 是不会超时的

由于数据小 所以dfs搜索最多矿就可以 不过要标记

代码及其注释:

#include<iostream>

#include<cstring>

#include<stack>

#include<cstdio>

#include<algorithm>

#include<queue>



using namespace std;



const int N=2005;

struct node

{

    struct tt *next;

    int ores;

}mem[N];

struct node1

{

    struct tt *next;

}mem1[N];

struct tt

{

    struct tt *next;

    int j;

};

int transfer[N];

int deep;

char path[50][50];

int low[N];

int dfn[N];

bool visited[N];

bool in[N];

stack<int>str;

int uppoint[N];

int sum[N];

int ans;

void build(int i,int j)

{

    struct tt *t=new tt;

    t->j=j;

    t->next=mem[i].next;

    mem[i].next=t;

}

void Clearlist(int n)//清理邻接表

{

    struct tt *t;

    for(int i=0;i<n;++i)

    {

        while(mem[i].next!=NULL)

        {

            t=mem[i].next;

            mem[i].next=t->next;

            delete t;

        }

        while(mem1[i].next!=NULL)

        {

            t=mem1[i].next;

            mem1[i].next=t->next;

            delete t;

        }

    }

}

void rebuild(int i,int j)

{

    struct tt *t=new tt;

    t->j=j;

    t->next=mem1[i].next;

    mem1[i].next=t;

}

void Tarjan(int x)

{//cout<<x<<endl;

    ++deep;

    dfn[x]=low[x]=deep;

    visited[x]=true;

    in[x]=true;

    str.push(x);

    struct tt *t=mem[x].next;

    while(t!=NULL)

    {

        if(visited[t->j]==false)

        {

            Tarjan(t->j);

            low[x]=min(low[x],low[t->j]);

        }else if(in[t->j]==true)

        {

            low[x]=min(low[x],dfn[t->j]);

        }

        t=t->next;

    }

    if(low[x]==dfn[x])

    {

        int num=0;

        while(str.top()!=x)

        {

            uppoint[str.top()]=x;//缩点

            in[str.top()]=false;

            num+=mem[str.top()].ores;//把环内每个点的量加起来

            str.pop();

        }

        uppoint[str.top()]=x;

        in[str.top()]=false;

        num+=mem[str.top()].ores;

        str.pop();

        sum[x]=num;

    }

}

int dist[N];

void dfsans(int x)

{

    if(mem1[x].next==NULL)//搜到头就看是不是答案

    {

        ans=max(ans,dist[x]);

        return ;

    }

    struct tt *t=mem1[x].next;

    while(t!=NULL)

    {

        if(dist[t->j]<dist[x]+sum[t->j])//只有可更新才往下搜

        {

            dist[t->j]=dist[x]+sum[t->j];

            dfsans(t->j);

        }

        t=t->next;

    }

}



void findans()

{

    memset(dist,-1,sizeof(dist));//有量为0 的情况 初始化要为-1

    dist[0]=sum[0];

    dfsans(0);

}

void dfs(int x)

{

    visited[x]=true;

    struct tt *t=mem[x].next;

    while(t!=NULL)

    {

        if(uppoint[x]!=uppoint[t->j])//属于不同的环则对两个环的缩点建边,即使t->j搜过了也得建边

        rebuild(uppoint[x],uppoint[t->j]);

        if(visited[t->j]==false)

        {

            dfs(t->j);

        }

        t=t->next;

    }

}

void rebuild_map()

{

    memset(visited,false,sizeof(visited));

    dfs(0);

}

int main()

{

    int T;

    int n,m;

    scanf("%d",&T);

    while(T--)

    {

        scanf("%d %d",&n,&m);

        getchar();

        for(int i=0;i<n;++i)

        {

            gets(path[i]);

        }

        int num=0;

        for(int i=0;i<n;++i)

        {

            for(int j=0;j<m;++j)

            {

                int I=i*m+j;//刚开始把m写成n了 当时怎么想的??

                if(path[i][j]=='#')

                {mem[I].ores=0;continue;}

                if(path[i][j]<='9'&&path[i][j]>='0')

                {

                    mem[I].ores=path[i][j]-'0';

                }

                else

                {

                    transfer[num]=I;++num;

                    mem[I].ores=0;

                }

                if(j+1<m&&path[i][j+1]!='#')

                build(I,i*m+j+1);

                if(i+1<n&&path[i+1][j]!='#')

                build(I,(i+1)*m+j);

            }

        }

        for(int i=0;i<num;++i)

        {

            int x,y;

            scanf("%d %d",&x,&y);

            if(path[x][y]!='#'&&(x*m+y)!=transfer[i])

            build(transfer[i],x*m+y);

        }

        memset(visited,false,sizeof(visited));

        memset(in,false,sizeof(in));

        while(!str.empty())

        str.pop();

        memset(uppoint,-1,sizeof(uppoint));

        memset(sum,0,sizeof(sum));

        deep=0;

        Tarjan(0);

        rebuild_map();//重新建图

        ans=0;

        findans();//找答案

        printf("%d\n",ans);

        Clearlist(n*m);

    }

    return 0;

}



 

你可能感兴趣的:(ant)