zoukankan      html  css  js  c++  java
  • 网络流24题

    前言

    目录在右边
    剩下的先咕咕咕,以后总会有的.

    P2756 飞行员配对方案问题

    传送门

    思路

    思路和下一个题差不多,差在二分图一边是外籍人,一边是英国人

    code

    #include <queue>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    #define N 20000
    #define M 1010
    
    using namespace std;
    const ll inf = 2004072600;
    int n, m, x, y;
    ll d, ans, dis[N];
    int add_edge = 1, now[N], head[N];
    struct node {
    	int next, to;
    	ll val;
    }edge[N];
    
    ll read() {
    	int s = 0, f = 0; char ch = getchar();
    	while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    void add(int from, int to, int dis) {
    	edge[++add_edge].next = head[from];
    	edge[add_edge].to = to;
    	edge[add_edge].val = dis;
    	head[from] = add_edge;
    	
    	edge[++add_edge].next = head[to];
    	edge[add_edge].to = from;
    	edge[add_edge].val = 0;
    	head[to] = add_edge;
    }
    
    inline int bfs() {
    	for (int i = 0; i <= n + 1; i++) dis[i] = inf;
    	queue<int> q; q.push(0), dis[0] = 0, now[0] = head[0];
    	while (!q.empty()) {
    		int x = q.front(); q.pop();
    		for (int i = head[x]; i; i = edge[i].next) {
    			int to = edge[i].to;
    			if (edge[i].val > 0 && dis[to] == inf) {
    				q.push(to);
    				now[to] = head[to];
    				dis[to] = dis[x] + 1;
    				if (to == n + 1) return 1;
    			}
    		}
    	}
    	return 0;
    }
    
    int dfs(int x, ll sum) {
    	if (x == n + 1) return sum;
    	ll k, res = 0;
    	for (int i = now[x]; i && sum; i = edge[i].next) {
    		now[x] = i;
    		int to = edge[i].to;
    		if (edge[i].val > 0 && (dis[to] == dis[x] + 1)) {
    			k = dfs(to, min(sum, edge[i].val));
    			if (k == 0) dis[to] = inf;
    			edge[i].val -= k;
    			edge[i ^ 1].val += k;
    			res += k, sum -= k;
    		}
    	}
    	return res;
    }
    
    int main() {
    	m = read(), n = read();
    	x = read(), y = read();
    	while (x != -1 && y != -1) {
    		add(x, y, 0x3f3f3f3f);
    		x = read(), y = read();
    	}
    	for (int i = 1; i <= m; i++) add(0, i, 1);
    	for (int i = m + 1; i <= n; i++) add(i, n + 1, 1);
    	while (bfs())
    		ans += dfs(0, inf);
    	cout << ans << "
    ";
    	for (int i = 2; i <= add_edge; i += 2) {
    		if (edge[i].to != 0 && edge[i ^ 1].to != 0) 
    		if (edge[i].to != n + 1 && edge[i ^ 1].to != n + 1) 
    		if (edge[i ^ 1].val != 0) 
    			printf("%d %d
    ", edge[i ^ 1].to, edge[i].to); 
    	}
    	return 0;
    }
    

    P3254 圆桌问题

    传送门

    思路

    可以很明显的想到,这个题我们可以网络流跑二分图(因为很快)

    我们把左边看成单位,右边看成第几个桌子

    因为题目中要求我们希望从同一个单位来的代表不在同一个餐桌就餐

    所以第一步就是让每一个单位向每一个桌子连一条边权为1的边。

    第二步:开一个超级源点,让每一个超级源点都往单位连一条边权为(r_i)的边,代表流量必须是这么大。

    第三步:开一个超级汇点,让每一个桌子都往超级汇点连一条边权为(c_i)的边,代表着每个人都必须有桌子坐

    最后我们跑一边最大流,然后看看能不能做开,即最大流量是不是与总人数相等

    code

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    #define N 1000010
    #define M 1010
    
    using namespace std;
    const ll inf = 2004072600;
    int n, m, x, y;
    ll d, ans, dis[N];
    int add_edge = 1, now[N], head[N];
    struct node {
    	int next, to;
    	ll val;
    }edge[N];
    
    int read() {
    	int s = 0, f = 0; char ch = getchar();
    	while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    void add(int from, int to, ll dis) {
    	edge[++add_edge].next = head[from];
    	edge[add_edge].to = to;
    	edge[add_edge].val = dis;
    	head[from] = add_edge;
    	
    	edge[++add_edge].next = head[to];
    	edge[add_edge].to = from;
    	edge[add_edge].val = 0;
    	head[to] = add_edge;
    }
    
    inline int bfs() {
    	for (int i = 0; i <= n + m + 1; i++) dis[i] = inf;
    	queue<int> q; q.push(0), dis[0] = 0, now[0] = head[0];
    	while (!q.empty()) {
    		int x = q.front(); q.pop();
    		for (int i = head[x]; i; i = edge[i].next) {
    			int to = edge[i].to;
    			if (edge[i].val > 0 && dis[to] == inf) {
    				q.push(to);
    				now[to] = head[to];
    				dis[to] = dis[x] + 1;
    				if (to == n + m + 1) return 1; 
    			}
    		}
    	}
    	return 0;
    }
    
    int dfs(int x, ll sum) {
    	if (x == n + m + 1) return sum;
    	ll k, res = 0;
    	for (int i = now[x]; i && sum; i = edge[i].next) {
    		now[x] = i;
    		int to = edge[i].to;
    		if (edge[i].val > 0 && (dis[to] == dis[x] + 1)) {
    			k = dfs(to, min(sum, edge[i].val));
    			if (k == 0) dis[to] = inf;
    			edge[i].val -= k;
    			edge[i ^ 1].val += k;
    			res += k, sum -= k;
    		}
    	}
    	return res;
    }
    
    void link() {
    	for (int i = 1; i <= n; i++)
    		for (int j = n + 1; j <= n + m; j++)
    			add(i, j, 1);
    	for (int i = 1, r; i <= n; i++) {
    		r = read();
    		add(0, i, r); ans += r;
    	}
    	for (int i = n + 1, c; i <= n + m; i++) {
    		c = read();
    		add(i, n + m + 1, c);
    	}
    }
    
    int main() {
    	n = read(), m = read();
    	link();
    	while (bfs())
    		ans -= dfs(0, inf);	
    	if (ans == 0) {
    		puts("1");	
    		for (int i = 1; i <= n; i++) {
    			for (int j = head[i]; j; j = edge[j].next) {
    				int to = edge[j].to;
    				if (to > n && to <= n + m && !edge[j].val)
    					printf("%d ", to - n);
    			}
    			puts("");
    		}
    	} else puts("0");
    }
    
  • 相关阅读:
    NBUT 1120 Reimu's Teleport (线段树)
    NBUT 1119 Patchouli's Books (STL应用)
    NBUT 1118 Marisa's Affair (排序统计,水)
    NBUT 1117 Kotiya's Incantation(字符输入处理)
    NBUT 1115 Cirno's Trick (水)
    NBUT 1114 Alice's Puppets(排序统计,水)
    188 Best Time to Buy and Sell Stock IV 买卖股票的最佳时机 IV
    187 Repeated DNA Sequences 重复的DNA序列
    179 Largest Number 把数组排成最大的数
    174 Dungeon Game 地下城游戏
  • 原文地址:https://www.cnblogs.com/zzz-hhh/p/13424639.html
Copyright © 2011-2022 走看看