zoukankan      html  css  js  c++  java
  • HDU-6532 Chessboard 2019广东省省赛B题(费用流)

    比赛场上很容易想到是费用流,但是没有想到建图方法qwq,太弱了。

    这里直接贴官方题解:

    费用流。离散化坐标,每行用一个点表示,每列也用一个点表示。表示第i-1行的点向表示第i行的点连边,容量为第i行及以后能拿的棋子数的上限,费用为0,同理表示相邻列的点两两连边。若第i行第j列上有棋子,则表示第i行的点向表示第j列的点连边,容量为1,费用为该棋子的价值。可以定义源点表示第0行,汇点表示第0列,源点到汇点的最大费用流即为答案。

    就是按照题解的建图方法,还有一些小细节:先要排序排除无用限制来减少限制边数,不然会超时。我用的办法是,按限制从小到大排序,大限制当且仅当它的行数小于小限制行数时才有用。列同理。这里想不明白的建议画图细细想。然后就是连边来表示限制条件:行的话就是(i-1)->i行连边,列的话就是i->(i-1)列连边,这是因为0行是源点0列是汇点所致的,行点要靠它的入边来限制流量,列点要靠出边来限制流量。

    细节详见代码及注释:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5000+10;
    const int M=100000+10;
    const int INF=0x3f3f3f3f;
    int n,m,r,c,s,t,maxflow,mincost;
    int nx,ny,x[N],y[N],xx[N],yy[N],bx[N],by[N];
    struct edge{
        int nxt,to,cap,cost;
    }edges[M<<1];
    int cnt=1,head[N],pre[N];
    
    struct dat{ int t,l; } R[M],C[M];
    bool cmp(dat a,dat b) { return a.l<b.l || a.l==b.l && a.t<b.t; }
    
    void add_edge(int x,int y,int z,int c) {
        edges[++cnt].nxt=head[x]; edges[cnt].to=y; edges[cnt].cap=z; edges[cnt].cost=c; head[x]=cnt;
    }
    
    queue<int> q;
    int dis[N],lim[N]; 
    bool inq[N];
    bool spfa(int s,int t) {
        while (!q.empty()) q.pop();
        memset(dis,0x3f,sizeof(dis));
        memset(inq,0,sizeof(inq));
        dis[s]=0; inq[s]=1; lim[s]=INF; q.push(s);
        while (!q.empty()) {
            int x=q.front(); q.pop();
            for (int i=head[x];i;i=edges[i].nxt) {
                edge e=edges[i];
                if (e.cap && dis[x]+e.cost<dis[e.to]) {
                    dis[e.to]=dis[x]+e.cost;
                    pre[e.to]=i;  //即e.to这个点是从i这条边来的 
                    lim[e.to]=min(lim[x],e.cap);
                    if (!inq[e.to]) { q.push(e.to); inq[e.to]=1; }
                }
            }
            inq[x]=0;
        }
        return !(dis[t]==INF); 
    }
    
    void MCMF() {
        maxflow=0; mincost=0;
        while (spfa(s,t)) {
            int now=t;
            maxflow+=lim[t];
            mincost+=lim[t]*dis[t];
            while (now!=s) {
                edges[pre[now]].cap-=lim[t];
                edges[pre[now]^1].cap+=lim[t];
                now=edges[pre[now]^1].to;
            }
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]),bx[i]=x[i],by[i]=y[i];
        nx=ny=n;
        scanf("%d",&m);
        char opt[3];
        for (int i=1;i<=m;i++) {
            int tx,ty; scanf("%s%d%d",opt,&tx,&ty);
            if (opt[0]=='R') R[++r]=(dat){tx,ty};
            if (opt[0]=='C') C[++c]=(dat){tx,ty};
        }
        int tmp=0; 
        sort(R+1,R+r+1,cmp);
        for (int i=1;i<=r;i++)  //排除行无用限制 
            if (tmp==0 || R[i].t<R[tmp].t) R[++tmp]=R[i],bx[++nx]=R[i].t;
        r=tmp; tmp=0;
        sort(C+1,C+c+1,cmp);
        for (int i=1;i<=c;i++)  //排除列无用限制 
            if (tmp==0 || C[i].t<C[tmp].t) C[++tmp]=C[i],by[++ny]=C[i].t;
        c=tmp;
        
        sort(bx+1,bx+nx+1); nx=unique(bx+1,bx+nx+1)-(bx+1);  //离散化 
        sort(by+1,by+ny+1); ny=unique(by+1,by+ny+1)-(by+1);  //离散化 
        
        for (int i=1;i<=n;i++) {
            int tx=lower_bound(bx+1,bx+nx+1,x[i])-bx;
            int ty=lower_bound(by+1,by+ny+1,y[i])-by;
            add_edge(tx,nx+1+ty,1,-i); add_edge(nx+1+ty,tx,0,i);  //棋子连边 
        }
        memset(xx,0x3f,sizeof(xx));
        memset(yy,0x3f,sizeof(yy));
        for (int i=1;i<=r;i++) {
            int tx=lower_bound(bx+1,bx+nx+1,R[i].t)-bx;
            xx[tx]=min(xx[tx],R[i].l);  //先求好限制条件,xx[i]代表i行及以后的最小限制 
        } 
        for (int i=1;i<=c;i++) {
            int ty=lower_bound(by+1,by+ny+1,C[i].t)-by;
            yy[ty]=min(yy[ty],C[i].l);  //列同行同理 
        }
        //这里是关键:行i-1->i为了限制i的出流,列i->i-1为了限制i的出流 
        for (int i=1;i<=nx;i++) add_edge(i-1,i,xx[i],0),add_edge(i,i-1,0,0);
        for (int i=1;i<=ny;i++) add_edge(nx+1+i,nx+1+i-1,yy[i],0),add_edge(nx+1+i-1,nx+1+i,0,0);
        
        s=0; t=nx+1;
        MCMF();
        cout<<-mincost<<endl;
        return 0;
    }
  • 相关阅读:
    apache安全—用户访问控制
    hdu 3232 Crossing Rivers 过河(数学期望)
    HDU 5418 Victor and World (可重复走的TSP问题,状压dp)
    UVA 11020 Efficient Solutions (BST,Splay树)
    UVA 11922 Permutation Transformer (Splay树)
    HYSBZ 1208 宠物收养所 (Splay树)
    HYSBZ 1503 郁闷的出纳员 (Splay树)
    HDU 5416 CRB and Tree (技巧)
    HDU 5414 CRB and String (字符串,模拟)
    HDU 5410 CRB and His Birthday (01背包,完全背包,混合)
  • 原文地址:https://www.cnblogs.com/clno1/p/10957772.html
Copyright © 2011-2022 走看看