UVA 10779 - Collectors Problem(网络流)

UVA 10779 - Collectors Problem

题目链接

题意:每个人有一种贴图,现在第0个人要去和别人交换贴图,来保证自己的贴图尽量多,只有别人没有该种贴图,并且自己有2张以上另一种贴图才会换,问最多有几张贴图

思路:最大流,关键在于如何建模,把0号人和物品连边,容量为有的容量,然后其他人如果物品等于0的,连一条边从物品到这个人,表示能交换,然后如果物品大于1的,连一条边从这个人到物品,容量为物品减1(自己要留一个),然后把所有物品连到汇点,跑一次最大流即可

代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXNODE = 1005;
const int MAXEDGE = 100005;

const int INF = 0x3f3f3f3f;

struct Edge {
	int u, v, cap, flow;
	Edge() {}
	Edge(int u, int v, int cap, int flow) {
		this->u = u;
		this->v = v;
		this->cap = cap;
		this->flow = flow;
	}
};

struct Dinic {
	int n, m, s, t;
	Edge edges[MAXEDGE];
	int first[MAXNODE];
	int next[MAXEDGE];
	bool vis[MAXNODE];
	int d[MAXNODE];
	int cur[MAXNODE];

	void init(int n) {
		this->n = n;
		memset(first, -1, sizeof(first));
		m = 0;
	}

	void add_Edge(int u, int v, int cap) {
		edges[m] = Edge(u, v, cap, 0);
		next[m] = first[u];
		first[u] = m++;
		edges[m] = Edge(v, u, 0, 0);
		next[m] = first[v];
		first[v] = m++;
	}

	bool bfs() {
		memset(vis, false, sizeof(vis));
		queue<int> Q;
		Q.push(s);
		d[s] = 0;
		vis[s] = true;
		while (!Q.empty()) {
			int u = Q.front(); Q.pop();
			for (int i = first[u]; i != -1; i = next[i]) {
				Edge& e = edges[i];
				if (!vis[e.v] && e.cap > e.flow) {
					vis[e.v] = true;
					d[e.v] = d[u] + 1;
					Q.push(e.v);
				}
			}
		}
		return vis[t];
	}

	int dfs(int u, int a) {
		if (u == t || a == 0) return a;
		int flow = 0, f;
		for (int &i = cur[u]; i != -1; i = next[i]) {
			Edge& e = edges[i];
			if (d[u] + 1 == d[e.v] && (f = dfs(e.v, min(a, e.cap - e.flow))) > 0) {
				e.flow += f;
				edges[i^1].flow -= f;
				flow += f;
				a -= f;
				if (a == 0) break;
			}
		}
		return flow;
	}

	int Maxflow(int s, int t) {
		this->s = s;
		this->t = t;
		int flow = 0;
		while (bfs()) {
			for (int i = 0; i < n; i++)
				cur[i] = first[i];
			flow += dfs(s, INF);
		}
		return flow;
	}
} gao;

const int N = 30;

int T, n, m, cnt[N];

int main() {
	int cas = 0;
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &n, &m);
		int s = 0, t = n + m;
		gao.init(t + 1);
		for (int i = 0; i < n; i++) {
			int tot, tmp;
			memset(cnt, 0, sizeof(cnt));
			scanf("%d", &tot);
			while (tot--) {
				scanf("%d", &tmp);
				cnt[tmp]++;
			}
			if (i == 0) {
				for (int j = 1; j <= m; j++)
					if (cnt[j] > 0) gao.add_Edge(i, j + n - 1, cnt[j]);
			} else {
				for (int j = 1; j <= m; j++) {
					if (cnt[j] > 1) gao.add_Edge(i, j + n - 1, cnt[j] - 1);
					if (cnt[j] == 0) gao.add_Edge(j + n - 1, i, 1);
				}
			}
		}
		for (int i = 1; i <= m; i++)
			gao.add_Edge(i + n - 1, t, 1);
		printf("Case #%d: %d\n", ++cas, gao.Maxflow(s, t));
	}
	return 0;
}
时间: 2024-10-19 13:11:30

UVA 10779 - Collectors Problem(网络流)的相关文章

UVA 10779 Collectors Problem 网络流+建图

题目链接:点击打开链接 题意:白书P370 思路: 因为问的是最后贴纸总数,那么就设最后的贴纸总数是网络流的答案. 首先我们模拟贴纸的流动过程: Bob 的 某种贴纸a -> 给一个没有a贴纸的人Peo -> 还给Bob一个Peo的某张重复贴纸 -> 这张贴纸可以算作答案了 #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include

UVA 10779 Collectors Problem[最大流]

from:neopenx 题目大意:Bob有一些贴纸,他可以和别人交换,他可以把自己独有的贴纸拿出去,也可以把重复的贴纸拿出去(有时候把独有的贴纸而不是重复的贴纸拿出去能换到更多贴纸). Bob的朋友也有一些贴纸,但是他们只会拿自己重复的贴纸和Bob换,而且换的是自己没有的贴纸. 求Bob最后最多能有多少种贴纸. 解题思路: 题目意思很明确了.就算把重复的贴纸拿出去也不一定最优,贪心就不用尝试了. 全局资源调配得使用网络流模型. 建图方式: ①S点(看作是Bob)->所有物品:连一条边,cap是

uva 10779 Collectors Problem

题目描述: Bob和他的朋友从糖果包装里收集贴纸.Bob和他的朋友总共n人.共有m种不同的贴纸.每人手里都有一些(可能有重复的)贴纸,并且只跟别人交换他所没有的贴纸.贴纸总是一对一交换.Bob比这些朋友更聪明,因为他意识到只跟别人交换自己没有的贴纸并不总是最优的.在某些情况下,换来一张重复的贴纸更划算.假设Bob的朋友只跟Bob交换(他们之间不交换),并且这些朋友只会出让手里的重复贴纸来交换他们没有的不同贴纸.你的任务是帮助Bob算出他最终可以得到的不同贴纸的最大数量.2 ≤ n ≤ 10, 5

UVA 10779 (最大流)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=33631 题目大意:Bob有一些贴纸,他可以和别人交换,他可以把自己独有的贴纸拿出去,也可以把重复的贴纸拿出去(有时候把独有的贴纸而不是重复的贴纸拿出去能换到更多贴纸). Bob的朋友也有一些贴纸,但是他们只会拿自己重复的贴纸和Bob换,而且换的是自己没有的贴纸. 求Bob最后最多能有多少种贴纸. 解题思路: 题目意思很明确了.就算把重复的贴纸拿出去也不一定最优,贪

HDU 4975 A simple Gaussian elimination problem. 网络流+矩阵上的dp

随机输出保平安啊 和hdu4888一个意思,先跑个网络流然后dp判可行. ==n^3的dp过不了,所以把n改成200. ==因为出题人没有把多解的情况放在200*200以外的矩阵. #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; const int MAX_N = 12

uva 11991 Easy Problem from Rujia Liu? Data Structure

// uva 11991 Easy Problem from Rujia Liu? // 给一个包含n个数的数组,需要回答若干个询问,每次询问两个整数 // k和v,输出从左到右第k个v的下标 // // 本题因为n比较大,所以直接开二维数组是不现实的 // 如果直接用vector的话,也是会有大量的浪费 // 所以可以先离散化一下,找到一共有多少个不同的数 // 再用vector动态数组就可以搞定了 // // 看着书上的map写的挺精彩的,我就习用了下来 // // 非常精彩,继续练吧...

uva 11991 - Easy Problem from Rujia Liu?(STL)

题目链接:uva 11991 - Easy Problem from Rujia Liu? 题目大意:给出一个包含n个整数的数组,你需要回答若干询问,每次询问两个整数k和v,输出从左到右第k个v的下标 解题思路:用map映射一个vector,对应即为map<int>即为一个可变长的数组,读取数组的时候将对应值放入即可. #include <cstdio> #include <cstring> #include <map> #include <vecto

UVA - 11898 Killer Problem

Description  Killer Problem  You are given an array of N integers and Q queries. Each query is a closed interval [l, r]. You should find the minimum absolute difference between all pairs in that interval. Input First line contains an integer T (T10).

UVA 11765 Component Placement 网络流 新姿势建图

题目链接:点击打开链接 题意: 给定n个物品, m个约束条件 把n个物品分到2个集合里 下面第一行表示i物品分到第一个集合里的花费 第二行表示分到第二个集合里的花费 第三行表示分物品的限制(1表示只能分到第一个集合,-1表示只能分到第二个集合,0无限制) 下面m行给出约束条件 u v cost 表示u v 两点必须能互相沟通,若两点已经在同一集合则花费为0 ,若不在同一集合则花费增加cost 问满足m个约束条件下的最小花费 思路: 首先感觉是网络流,==建图比较难想 用流量表示费用 1.若i点放