T3 网格游走

  • 本质上是一道trajan构图+floodfill+期望的壳子
  • 对于高度来说,我们自然需要重新建图:-》知识点:二维变成一维的图
return (x-1)*m+y
  • 那么新图就建出来了:同时我们可以考虑(现在这个图是DAG吗?显然不是,那么我们往往特殊走:如果一块之间是DAG我们会怎么处理
  • 如果是DAG的话,我们显然可以从多个入度为0(对于DAG一定要关注入度或者出度为0的点)进入队列,然后用floodfill的思想从多个角度top序更新
  • 那么:怎么样才能够锁点?:
  • trajan缩完点之后,我们要关注的是缩完点之后的点的性质:以本题为例,缩完之后的点贡献期望是多少
  • 这时候需要根据期望的递推式进行记忆化搜搜:
  •  

     最后一定要关注一个东西:用暴力求解得出来的答案可以尝试打表一下观察他们的特殊性:本题 fi=2i

  • 代码:
  • #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    
    #define ll long long
    
    using namespace std;
    
    inline int read()
    {
        int s=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*f;
    }
    
    const int N=3e6+1,M=3e6+1,L=1e6+1;
    
    struct Edge
    {
        int nxt,to;
        void make(int _nxt,int _to){nxt=_nxt;to=_to;}
    }edge1[2*M+1],edge2[2*M+1];
    int edge1_tot,edge2_tot,head1[N],head2[N];
    void edge1_add(int x,int y){edge1[++edge1_tot].make(head1[x],y);head1[x]=edge1_tot;}
    void edge2_add(int x,int y){edge2[++edge2_tot].make(head2[x],y);head2[x]=edge2_tot;}
    
    int n,m,tim,dfn[N],low[N],stc[N],top,color,co[N],dd[N];ll dis[N],f[1000001],v[1000001];
    int change(int x,int y){return (x-1)*m+y;}
    void tarjan(int u)
    {
        dfn[u]=low[u]=++tim;
        stc[++top]=u;
        for(int i=head1[u];i;i=edge1[i].nxt)
        {
            int v=edge1[i].to;
            if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);}
            else if(!co[v])low[u]=min(low[u],dfn[v]);
        }
        if(dfn[u]==low[u])
        {
            co[u]=++color;
            dis[color]=v[u];dd[color]=1;
            while(stc[top]!=u)
            {
                co[stc[top]]=color;
                dis[color]+=v[stc[top]];
                dd[color]++;
                top--;
            }
            top--;
        }
    }
    
    struct node
    {
        int x,y,op;
        void make(int _x,int _y,int _op){x=_x;y=_y;op=_op;}
    }dian[N];
    
    int h[1001][1001],dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1},du[1000001];
    
    int main()
    {
        freopen("road.in","r",stdin);
        freopen("road.out","w",stdout);
        n=read(),m=read();
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        h[i][j]=read();
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        v[change(i,j)]=read();
    
        
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            for(int k=1;k<=4;k++)
            {
                int x=i+dx[k],y=j+dy[k];
                if(x<=0||y<=0||x>n||y>m)continue;
                int k1=change(i,j),k2=change(x,y);
                if(h[i][j]<h[x][y])swap(k1,k2);
                edge1_add(k1,k2);
            }
        }
        
        for(int i=1;i<=n*m;i++)if(!dfn[i])tarjan(i);
        for(int i=1;i<=n*m;i++)
        for(int j=head1[i];j;j=edge1[j].nxt)
        {
            int v=edge1[j].to;
            if(co[i]==co[v])continue;
            edge2_add(co[i],co[v]);
            du[co[v]]++;
        }
        
        queue<int>q;ll ans=0;
        for(int i=1;i<=color;i++)
        {
            if(!du[i])q.push(i);
        //    printf("%lld\n",dis[i]);
        }
        while(!q.empty())
        {
            int u=q.front();q.pop();
            if(dd[u]!=1)f[u]+=2ll*dis[u];
            else f[u]+=dis[u];
            ans=max(ans,f[u]);
            for(int i=head2[u];i;i=edge2[i].nxt)
            {
                int v=edge2[i].to;
                if(!--du[v])q.push(v);
                f[v]=max(f[v],f[u]);
            }
        }
        
        printf("%lld\n",ans);
        
        return 0;
    }

     

  • fread优化:
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cctype>
    
    using namespace std;
    
    const int S = 1 << 20;
    char frd[S], *hed = frd + S;
    const char *tal = hed;
    
    inline char nxtChar()
    {
        if (hed == tal)
            fread(frd, 1, S, stdin), hed = frd;
        return *hed++;
    }
    
    template <class T>
    inline void read(T &res)
    {
        char ch; 
        while (ch = nxtChar(), !isdigit(ch));
        res = ch ^ 48;
        while (ch = nxtChar(), isdigit(ch))
            res = res * 10 + ch - 48;
    }
    
    typedef long long ll;
    const int dx[] = {-1, 1, 0, 0},
              dy[] = {0, 0, -1, 1};
    const int N = 1005, M = 1e6 + 5;
    int h[N][N], v[N][N], num[N][N], rin[M];
    int dfn[M], low[M], stk[M], col[M], point[M], val[M];
    ll f[M], unt[M], ans;
    int n, m, G, C, top, tis; bool inv[M];
    
    struct Edge
    {
        int to; Edge *nxt;
    };
    
    struct Graph
    {
        Edge p[M << 2], *lst[M], *P;
        
        inline void Init()
        {
            P = p;
        } 
        
        inline void addEdge(int x, int y)
        {
            (++P)->nxt = lst[x]; lst[x] = P; P->to = y;
        } 
    }newG, oldG;
    
    inline bool check(int x, int y)
    {
        return x >= 1 && x <= n && y >= 1 && y <= m;
    }
    
    template <class T>
    inline void CkMin(T &x, T y) {if (x > y) x = y;}
    template <class T>
    inline void CkMax(T &x, T y) {if (x < y) x = y;}
    
    inline void Tarjan(int x)
    {
        dfn[x] = low[x] = ++tis; int y;
        stk[++top] = x; inv[x] = true;
        for (Edge *e = oldG.lst[x]; e; e = e->nxt)
            if (!dfn[y = e->to])
                Tarjan(y), CkMin(low[x], low[y]);
            else if (inv[y])
                CkMin(low[x], dfn[y]);
        if (dfn[x] == low[x])
        {
            inv[x] = false; col[x] = ++C; 
            point[C] = 1; unt[C] = val[x];
            while (y = stk[top--], y != x)
                inv[y] = false, col[y] = C, unt[C] += val[y], ++point[C];
        }
    }
    
    int main()
    {
        freopen("road.in", "r", stdin);
        freopen("road.out", "w", stdout);
        oldG.Init(); newG.Init();
        read(n); read(m);
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                read(h[i][j]);
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                read(v[i][j]);
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                num[i][j] = ++G, val[G] = v[i][j];
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                for (int k = 0; k < 4; ++k)
                {
                    int tx = i + dx[k],
                        ty = j + dy[k];
                    if (check(tx, ty) && h[tx][ty] <= h[i][j])
                        oldG.addEdge(num[i][j], num[tx][ty]);
                }
        for (int i = 1; i <= G; ++i)
            if (!dfn[i]) Tarjan(i);
        for (int i = 1; i <= C; ++i)
            if (point[i] > 1) unt[i] = unt[i] << 1ll;
        for (int i = 1; i <= G; ++i)
            for (Edge *e = oldG.lst[i]; e; e = e->nxt)
            {
                int y = e->to;
                if (col[i] == col[y]) continue;
                newG.addEdge(col[i], col[y]); ++rin[col[y]];
            } 
        for (int i = 1; i <= C; ++i)
            if (!rin[i]) stk[++top] = i, f[i] = unt[i];
        int x, y;
        while (top)
        {
            x = stk[top--];
            for (Edge *e = newG.lst[x]; e; e = e->nxt)
            {
                if (!--rin[y = e->to]) stk[++top] = y;
                CkMax(f[y], f[x] + unt[y]);
            }
        }
        for (int i = 1; i <= C; ++i)
            CkMax(ans, f[i]);
        cout << ans << endl;
    } 
    View Code

     

posted @ 2020-10-27 13:21  ILH  阅读(119)  评论(0)    收藏  举报