zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    Spring注解(环境)
    Spring注解(赋值相关)
    C#:关联程序和文件
    C#: 获取执行程序所在路径和启动资源管理器
    C#:WPF绘制问题
    WPF:窗体置顶
    C#:屏幕显示区域问题
    C#:文件、文件夹特别操作
    C#:插件、框架
    WPF:MenuItem样式
  • 原文地址:https://www.cnblogs.com/liulangye/p/2531265.html
Copyright © 2011-2022 走看看