• BZOJ2547 CTSC2002玩具兵(最短路径+二分答案+最大流)


      先不考虑只有一个显得有些特殊的天兵。

      可以发现超能力的作用实质上是使兵更换职业。每一个兵到达某个位置最少需要更换职业的次数是彼此独立的,因为如果需要某两人互换职业可以使他们各自以当前职业到达需要到的地方,不会造成其中一个次数增加。

      于是预处理出每个兵到达每个位置的最少代价。之后二分答案,把每个兵向可以到达的目标位置连边。跑最大流就可以知道是否可行。

      最后考虑天兵。天兵可以任意游走,并且与天兵换职业的兵可以直接到达目的地。那么在最大流的结果上加上二分出的答案即可,因为每次使用超能力都可以送走一个兵。

      1A爽爆。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 110
    int n,m,k,l,dis[N][N][N],a[N][N],w[N][N],ans;
    struct pos{int x,y;}u[N],v[N];
    namespace shortestpath
    {
        int d[N*N<<1],p[N*N<<1],t=0;
        int wx[4]={1,0,-1,0},wy[4]={0,1,0,-1};
        bool flag[N*N<<1];
        struct data{int to,nxt,len;}edge[N*N<<4];
        int trans(int x,int y,int op){return op*n*m+(x-1)*m+y;}
        void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
        struct data2
        {
            int x,d;
            bool operator <(const data2&a) const
            {
                return d>a.d;
            }
        };
        priority_queue<data2> q;
        void make()
        {
            for (int i=1;i<=n;i++)
                for (int j=1;j<=m;j++)
                {
                    for (int k=0;k<4;k++)
                    if (i+wx[k]>0&&i+wx[k]<=n&&j+wy[k]>0&&j+wy[k]<=m)
                    if (a[i][j]<a[i+wx[k]][j+wy[k]])
                        addedge(trans(i,j,0),trans(i+wx[k],j+wy[k],0),0),
                        addedge(trans(i,j,1),trans(i+wx[k],j+wy[k],0),1);
                    else if (a[i][j]>a[i+wx[k]][j+wy[k]])
                        addedge(trans(i,j,0),trans(i+wx[k],j+wy[k],1),1),
                        addedge(trans(i,j,1),trans(i+wx[k],j+wy[k],1),0);
                    else
                        addedge(trans(i,j,0),trans(i+wx[k],j+wy[k],0),0),
                        addedge(trans(i,j,1),trans(i+wx[k],j+wy[k],1),0);
                }
        }
        void dijkstra(int start)
        {
            memset(d,42,sizeof(d));d[trans(u[start].x,u[start].y,start>k)]=0;
            memset(flag,0,sizeof(flag));
            while (!q.empty()) q.pop();
            q.push((data2){trans(u[start].x,u[start].y,start>k),0});
            for (int i=1;i<=(n*m<<1);i++)
            {
                while (!q.empty()&&flag[q.top().x]) q.pop();
                if (q.empty()) break;
                data2 v=q.top();q.pop();
                flag[v.x]=1;
                for (int j=p[v.x];j;j=edge[j].nxt)
                if (v.d+edge[j].len<d[edge[j].to])
                {
                    d[edge[j].to]=v.d+edge[j].len;
                    q.push((data2){edge[j].to,d[edge[j].to]});
                }
            }
            for (int i=1;i<=n;i++)
                for (int j=1;j<=m;j++)
                dis[start][i][j]=min(d[trans(i,j,0)],d[trans(i,j,1)]);
        }
    }
    namespace maxflow
    {
        const int S=0,T=201;
        int ans,p[N<<1],d[N<<1],q[N<<1],cur[N<<1],t;
        struct data{int to,nxt,cap,flow;}edge[N*N<<2];
        void addedge(int x,int y,int z)
        {
            t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=0,p[x]=t;
            t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=0,edge[t].flow=0,p[y]=t;
        }
        bool bfs()
        {
            memset(d,255,sizeof(d));d[S]=0;
            int head=0,tail=1;q[1]=S;
            do
            {
                int x=q[++head];
                for (int i=p[x];~i;i=edge[i].nxt)
                if (d[edge[i].to]==-1&&edge[i].flow<edge[i].cap)
                {
                    d[edge[i].to]=d[x]+1;
                    q[++tail]=edge[i].to;
                }
            }while (head<tail);
            return ~d[T];
        }
        int work(int k,int f)
        {
            if (k==T) return f;
            int used=0;
            for (int i=cur[k];~i;i=edge[i].nxt)
            if (d[k]+1==d[edge[i].to])
            {
                int w=work(edge[i].to,min(edge[i].cap-edge[i].flow,f-used));
                edge[i].flow+=w,edge[i^1].flow-=w;
                if (edge[i].flow<edge[i].cap) cur[k]=i;
                used+=w;if (used==f) return f;
            }
            if (used==0) d[k]=-1;
            return used;
        }
        void make(int lim)
        {
            t=-1;memset(p,255,sizeof(p));
            for (int i=1;i<=(k<<1);i++) addedge(S,i,1);
            for (int i=1;i<=l;i++) addedge((k<<1)+i,T,w[v[i].x][v[i].y]);
            for (int i=1;i<=(k<<1);i++)
                for (int j=1;j<=l;j++)
                if (dis[i][v[j].x][v[j].y]<=lim) addedge(i,(k<<1)+j,1);
        }
        int dinic(int lim)
        {
            make(lim);
            ans=0;
            while (bfs())
            {
                memcpy(cur,p,sizeof(p));
                ans+=work(S,N);
            }
            return ans;
        }
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj2547.in","r",stdin);
        freopen("bzoj2547.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read(),k=read(),l=read();
        for (int i=1;i<=(k<<1|1);i++) u[i].x=read(),u[i].y=read();
        for (int i=1;i<=l;i++) v[i].x=read(),v[i].y=read(),w[v[i].x][v[i].y]=read();
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
            a[i][j]=read();
        shortestpath::make();
        for (int i=1;i<=(k<<1);i++) shortestpath::dijkstra(i);
        int l=0,r=k<<1,ans;
        while (l<=r)
        {
            int mid=l+r>>1;
            if (maxflow::dinic(mid)+mid>=(k<<1)) ans=mid,r=mid-1;
            else l=mid+1;
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    【opencv.js】将图片转换为灰度图
    【快速创建】第一个 opencv.js 项目
    【踩坑无数】Anaconda(2020.02) + Tensorflow2.1 + python3.7 (CPU版本)的安装
    Thread的join方法
    常用语句
    获取当前托管线程的唯一标识符
    修改文件或文件夹的权限,为指定用户、用户组添加完全控制权限(转载)
    C#中Monitor和Lock以及区别(转载)
    LIBRA查询
    Select()和SelectMany()的区别
  • 原文地址:https://www.cnblogs.com/Gloid/p/9588290.html
Copyright © 2020-2023  润新知