zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    杭电 Problem
    杭电Problem 5053 the sum of cube 【数学公式】
    杭电 Problem 2089 不要62 【打表】
    杭电 Problem 4548 美素数【打表】
    杭电 Problem 2008 分拆素数和 【打表】
    杭电 Problem 1722 Cake 【gcd】
    杭电 Problem 2187 悼念512汶川大地震遇难同胞——老人是真饿了【贪心】
    杭电Problem 1872 稳定排序
    杭电 Problem 1753 大明A+B
    东北林业大 564 汉诺塔
  • 原文地址:https://www.cnblogs.com/Gloid/p/9588290.html
Copyright © 2011-2022 走看看