zoukankan      html  css  js  c++  java
  • 2019湘潭邀请赛A

    看到题目的时候就感觉是一个费用流

    但是怎么想都想不出来怎么做(太菜了)

    最大的问题大概是我把这个网格看成了若干个点,而没有思考它们在行列上的关系
    对于两个R限制,每次一定有一个限制是基于前一个限制的,例如R 1 10和R 3 5,3>1,所以3行及之后的点一定是先满足前一个条件,再满足这一个条件,基于此,我们把点按照行排序,向第一个被限制的点从s连上容量为k的边,然后再依排序顺序一个个连其他的所有受限制的边,容量为inf,对于下一个限制,找到第一个被限制的点,从上一个点到这个点的容量改成k,这样就可以做到限制每一行的效果。

    但是,还有一个列的要求,当然我觉得应该可以再按照列排序,然后用刚刚的方法连接(未验证)。分析连边的特点,是按照行或者列的顺序连边的,所以我们可以先离散化坐标,每个方格就用它所在的行和列之间的连边来表示,刚刚的边就转换成了行与行和列与列之间的连边,用费用列求解即可

    需要注意的是,列是要倒着连边的,以为列流向汇点

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1010;
    typedef long long ll;
    struct Edge {
        int from, to, w, cap, flow;
    };
    const int INF = 0x3f3f3f3f;
    struct MCMF {
        vector < Edge > edge;
        vector < int > G[N];
        bool vis[N];
        int cur[N], d[N], s, t;
        ll ret = 0;
        inline void Add(int from, int to, int w, int cap){
            edge.push_back((Edge){from, to, w, cap, 0});
            edge.push_back((Edge){to, from, -w, 0, 0}); //注意这里,w是相反的数
            int m = edge.size();
            G[from].push_back(m - 2);
            G[to].push_back(m - 1);
        }
    
        inline bool SPFA(){
            memset(d, 0x3f, sizeof(d));
            queue < int > q;
            q.push(s);
            d[s] = 0;
            vis[s] = 1;
            while(!q.empty()){
                int u = q.front(); q.pop();
                vis[u] = false;
                for (int i = 0; i < G[u].size(); i++) {
                    Edge& e = edge[G[u][i]];
                    if (d[e.to] > d[u] + e.w && e.cap > e.flow) {
                        d[e.to] = d[u] + e.w;
                        if (!vis[e.to]) q.push(e.to), vis[e.to] = true;
                    }
                                }
            }
            return d[t] != INF;
        }
    
        int dfs(int x, int a){
            if (x == t || a == 0)    return a;
            int flow = 0, f; vis[x] = true; //因为可能有0边,不像单纯的最大流能保证是+1
            for (int& i = cur[x]; i < G[x].size(); i++) {
                Edge& e = edge[G[x][i]];
                if (!vis[e.to] && d[x] + e.w == d[e.to] && (f = dfs(e.to, min(e.cap - e.flow, a))) > 0){
                    e.flow += f;
                    edge[G[x][i] ^ 1].flow -= f;
                    flow += f;
                    a -= f; ret += 1ll * e.w * f;
                    if (a == 0)    break;
                }
            }
            vis[x] = false;
            return flow;
        }
    
        inline int mcmf(){
            int ans = 0;
            while(SPFA()){
                memset(cur, 0, sizeof(cur));
                ans += dfs(s, INF);
            }
            return ans;
        }
    }D;
    int a[N], b[N], x[N], y[N];
    int minn[2][N];
    int main() {
    	int n;
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) {
    		scanf("%d%d", &x[i], &y[i]);
    		a[i] = x[i]; b[i] = y[i];
    	}
    	sort(a + 1, a + n + 1);
    	sort(b + 1, b + n + 1);
    	int newx = unique(a + 1, a + n + 1) - a - 1;
    	int newy = unique(b + 1, b + n + 1) - b - 1;
    	for (int i = 1; i <= n; i++) {
    		int p1 = lower_bound(a + 1, a + newx + 1, x[i]) - a;
    		int p2 = lower_bound(b + 1, b + newy + 1, y[i]) - b;
    		D.Add(p1, p2 + n + 1, -i, 1);
    	}
    	int m;
    	scanf("%d", &m);
    	memset(minn, 0x3f, sizeof(minn));
    	for (int i = 1; i <= m; i++) {
    		char s[3];
    		int j, k;
    		scanf("%s%d%d", s, &j, &k);
    		if (s[0] == 'R') {
    			int p = lower_bound(a + 1, a + newx + 1, j) - a;
    			minn[0][p] = min(k, minn[0][p]);
    		}
    		else {
    			int p = lower_bound(b + 1, b + newy + 1, j) - b;
    			minn[1][p] = min(k, minn[0][p]);
    		}
    	}
    	for (int i = 1; i <= newx || i <= newy; i++) {
    		if (i <= newx)	
    			D.Add(i - 1, i, 0, minn[0][i]);
    		if (i <= newy)	
    			D.Add(i + n + 1, i + n, 0, minn[1][i]);
    	}
    	D.s = 0; D.t = n + 1;
    	D.mcmf();
    	printf("%lld
    ", -D.ret);
    	return 0;
    }
    
  • 相关阅读:
    C++ new 解析重载 .
    __cdecl,__fastcall, __stdcall 什么区别? .
    C++构造函数调用顺序
    用gdb调试core dump文件
    placement new(转)
    [精华] 跟我一起写 Makefile
    使用 GDB 调试多进程程序
    第37条:避免对函数中继承得来的默认参数值进行重定义
    程序只运行一个是实例 .
    南通SEO:单页的SEO元素
  • 原文地址:https://www.cnblogs.com/cminus/p/14790373.html
Copyright © 2011-2022 走看看