• [APIO2013]


    A.机器人

    题目大意:给定一个n*m的地图,有一些障碍物和k个机器人,你每次可以选择一个机器人往任意一个方向推,遇到转向器会转向,两个编号相邻的机器人可以合并,求最少推多少次可以全部合并。

    $n,mleqslant 500 kleqslant 9$

    题解:用f[i][j][k][l]表示i到j的机器人在(k,l)合并的最小次数,那么当(k',l')推一次可以到(k,l)的时候,它可以从f[i][j][k'][l']+1转移。当然,它还可以从f[i][p][k][l]+f[p+1][j][k][l]转移,所以我们先计算出

    所有点推一次到哪里,每次做完一个f[i][j]之后,就做一次spfa。

    但是spfa会T,并不能过。我们考虑开两个队列,在spfa之前把起始的位置拍好序扔到队列1,然后每次取出两个队列队头较小的松弛,松弛到的点加入队列2,这样可以保证队列1和队列2有序,spfa就进化为了bfs,排序最好用O(n)的计数排序,跑的飞快。

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define INF 32639
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    unsigned short d[11][11][501][501];int mark[501][501][4],top=0;
    int n,h,w,cnt=0,L,R;
    int v[180005],sa[180005];
    char st[501][501];
    struct P{short x,y;
        P(short x=0,short y=0):x(x),y(y){}
        bool operator !(){return x==0&&y==0;}
    }pos[11],to[505][505][4],q[180005];
    bool b[501][501];
    const int dis[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
    queue<P> q1,q2;
    
    P dfs(int x,int y,int dir)
    {    
        if(mark[x][y][dir]==cnt) return to[x][y][dir]=P(-1,-1);mark[x][y][dir]=cnt;
        if(!(!to[x][y][dir])) return to[x][y][dir];    
        int pre=dir;
        if(st[x][y]=='A') dir=(dir+3)%4;
        if(st[x][y]=='C') dir=(dir+1)%4;
        int xx=x+dis[dir][0],yy=y+dis[dir][1];
        if(xx<1||yy<1||xx>h||yy>w||st[xx][yy]=='x') return to[x][y][pre]=P(x,y);
        return to[x][y][pre]=dfs(xx,yy,dir);
    }
    
    void spfa()
    {
        memset(v,0,sizeof(v));
        for(int i=1;i<=top;i++)v[d[L][R][q[i].x][q[i].y]]++;
        for(int i=1;i<=INF;i++)v[i]+=v[i-1];
        for(int i=1;i<=top;i++) sa[v[d[L][R][q[i].x][q[i].y]]--]=i;
        for(int i=1;i<=top;i++) q1.push(q[sa[i]]); 
        top=0;
        while((!q1.empty())||(!q2.empty()))
        {
            P now;
            if(q1.empty()||((!q2.empty())&&d[L][R][q1.front().x][q1.front().y]>d[L][R][q2.front().x][q2.front().y]))
                now=q2.front(),q2.pop();
            else 
                now=q1.front(),q1.pop();
            b[now.x][now.y]=0;
            for(int i=0;i<4;i++)
            {
                P t=to[now.x][now.y][i];         
                if(t.x==-1||t.y==-1) continue;    
                if(d[L][R][now.x][now.y]+1<d[L][R][t.x][t.y])
                {
                    d[L][R][t.x][t.y]=d[L][R][now.x][now.y]+1;
                    if(!b[t.x][t.y])
                    {
                        b[t.x][t.y]=1;
                        q2.push(t);
                    }
                }
            }
    
        }
    }
    
    int main()
    {
        n=read();w=read();h=read();
        memset(d,127,sizeof(d));
        for(int i=1;i<=h;i++)
        {
            scanf("%s",st[i]+1);
            for(int j=1;j<=w;j++)
                if(st[i][j]>'0'&&st[i][j]<='9')
                    pos[st[i][j]-'0']=P(i,j);
        }
        for(int i=1;i<=h;i++)
            for(int j=1;j<=w;j++)
                if(st[i][j]!='x')
                    for(int k=0;k<4;k++)
                        ++cnt,dfs(i,j,k);
        for(int i=1;i<=n;i++)
        {
            b[pos[i].x][pos[i].y]=1;q[++top]=pos[i];
            L=R=i;d[i][i][pos[i].x][pos[i].y]=0;spfa();
        }
        for(int l=2,j;l<=n;l++)
            for(int i=1;(j=i+l-1)<=n;i++)
            {
                for(int x=1;x<=h;x++)
                    for(int y=1;y<=w;y++)
                    {
                        for(int k=i;k<j;k++)
                            d[i][j][x][y]=min(d[i][j][x][y],(unsigned short)(d[i][k][x][y]+d[k+1][j][x][y]));
                        if(d[i][j][x][y]<INF)
                            q[++top]=P(x,y),b[x][y]=1;
                    }
                L=i;R=j;spfa();
            }
        unsigned short ans=30000;
        for(int i=1;i<=h;i++)
            for(int j=1;j<=w;j++)
                ans=min(ans,d[1][n][i][j]);
        if(ans<30000) printf("%u
    ",ans);
        else puts("-1");
        return 0;
    }

     B.[Apio2013]道路费用

     

     $nleqslant 10^{5},mleqslant 3*10^{5},kleqslant 20$

    题解:强制选这K条边,然后我们发现K条边把整个图割成了K+1块,每一块内选的边肯定是相同的。我们把这几块缩点,然后枚举每条边选不选,对每种情况,暴力算出每条边的最大长度,通过dp算出这种情况的答案就可以啦。

    复杂度$mlogm+k^{2}*2^{k}$

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    #define INF 200000000000000000LL
    #define MN 100000
    #define MM 300000
    #define MK 20
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    
    struct edge{
        int from,to;ll w;int kind;
    }e[MM+MK+5],ek[MK+5],e3[MK+5]; 
    struct nedge{int to,next,kind;}e2[MN*2+5];
    ll ans=0,sum[MK+5],p[MN+5],val[MK+5],mn[MK+5];
    int n,m,K,cnt=0,s[MN+5],head[MN+5],cn=0,bel[MN+5],dep[MK+5],fa2[MK+5];
    bool mark[MN+5],b[MK+5];
    
    bool cmp(edge x,edge y){return x.w<y.w||(x.w==y.w&&x.kind>y.kind);}
    int find(int x)
    {
        return !s[x]?x:s[x]=find(s[x]);
    }
    
    void ins(int f,int t,int kind=0)
    {
        e2[++cnt]=(nedge){t,head[f],kind};head[f]=cnt;
        e2[++cnt]=(nedge){f,head[t],kind};head[t]=cnt;
    }
    
    void kruscal()
    {
        for(int i=1;i<=K;i++)
        {
            int x=find(ek[i].from),y=find(ek[i].to);
            s[x]=y,ins(ek[i].from,ek[i].to,1);
        }
        for(int i=1;i<=m;i++)
        {
            int x=find(e[i].from),y=find(e[i].to);
            if(x!=y)s[x]=y,ins(e[i].from,e[i].to,0);
        }
    }
    
    void getv(int x)
    {
        mark[x]=1;bel[x]=cn;val[cn]+=p[x];
        for(int i=head[x];i;i=e2[i].next)
            if(!mark[e2[i].to]&&!e2[i].kind)
                getv(e2[i].to);
    }
    
    void dp(int x,int fa)
    {
        sum[x]=val[x];fa2[x]=fa;
        for(int i=head[x];i;i=e2[i].next)
            if(e2[i].to!=fa)
            {
                dep[e2[i].to]=dep[x]+1;
                dp(e2[i].to,x);sum[x]+=sum[e2[i].to];
            }
    }
    int tms=0;
    void solve()
    {
        ll tot=0;cnt=0;
        for(int i=1;i<=cn;i++)s[i]=0,head[i]=0,mn[i]=INF;
        for(int i=1;i<=K;i++)
            if(b[i])
            {
                int x=find(ek[i].from),y=find(ek[i].to);
                if(x==y)return;s[x]=y;ins(ek[i].from,ek[i].to);
            }
        tms++;
        for(int i=1;i<=K;i++)
        {
            int x=find(e3[i].from),y=find(e3[i].to);
            if(x!=y) s[x]=y,ins(e3[i].from,e3[i].to);
        }
        dp(1,0);
        for(int i=1;i<=K;i++)
        {
            int u=e3[i].from,v=e3[i].to;
            if(dep[u]<dep[v]) swap(u,v);
            while(dep[u]>dep[v]) mn[u]=min(mn[u],e3[i].w),u=fa2[u];
            while(u!=v)
            {
                mn[u]=min(mn[u],e3[i].w);
                mn[v]=min(mn[v],e3[i].w);
                u=fa2[u],v=fa2[v];
            }
        }
        for(int i=1;i<=K;i++) if(b[i])
        {
            int u=ek[i].from,v=ek[i].to;
            if(dep[u]<dep[v]) swap(u,v);
            tot+=1LL*mn[u]*sum[u];
        }
        ans=max(ans,tot);
    }
    
    void dfs(int x)
    {
        if(x>K)
        {
            solve();
            return;
        }
        b[x]=1;dfs(x+1);
        b[x]=0;dfs(x+1);
    }
    
    int main()
    {
        n=read();m=read();K=read();
        for(int i=1;i<=m;i++)
            e[i].from=read(),e[i].to=read(),e[i].w=read();
        for(int i=1;i<=K;i++)
            ek[i].from=read(),ek[i].to=read();
        for(int i=1;i<=n;i++)p[i]=read();
        sort(e+1,e+m+1,cmp);kruscal();
        for(int i=1;i<=n;i++)if(!mark[i]) ++cn,getv(i);
        cnt=0;
        for(int i=1;i<=cn;i++) s[i]=0;
        for(int i=1;i<=m+K;i++) if(!e[i].kind)
        {
            int x=bel[e[i].from],y=bel[e[i].to],f1=find(x),f2=find(y);
            if(f1!=f2) s[f1]=f2,e3[++cnt]=(edge){x,y,e[i].w,0};
        }
        for(int i=1;i<=K;i++) ek[i].from=bel[ek[i].from],ek[i].to=bel[ek[i].to];
        dfs(1);
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    js识别键盘操作
    抽奖活动 算法设计
    Eureka 配置项说明
    manjaro 更新chrome报签名错误
    manjaro系统上使用asdf安装php注意事项
    Failed to load config "react-app" to extend from.
    YarnV2 install
    银河麒麟安装达梦数据库失败Unable to load native library: libnsl.so.1: cannot open shared object file: No such file or directory
    Net5中使用Swagger
    编译Windows 版本的Redis 6.x
  • 原文地址:https://www.cnblogs.com/FallDream/p/apio2013.html
Copyright © 2020-2023  润新知