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;
    }
  • 相关阅读:
    爬虫大作业之爬取笔趣阁小说
    数据结构化与保存
    使用正则表达式,取得点击次数,函数抽离
    爬取校园新闻首页的新闻
    网络爬虫练习
    Hadoop综合大作业
    理解MapReduce
    熟悉常用的HBase操作
    熟悉常用的HDFS操作
    爬虫大作业
  • 原文地址:https://www.cnblogs.com/clno1/p/10957772.html
Copyright © 2011-2022 走看看