【线性规划与网络流 24题】已完成(3道题因为某些奇怪的原因被抛弃了QAQ)

写在前面:SDOI2016 Round1滚粗后蒟蒻开始做网络流来自我拯救(2016-04-11再过几天就要考先修课,现在做网络流24题貌似没什么用←退役节奏)

做的题目将附上日期,见证我龟速刷题。

1.飞行员配对方案问题 2016-04-11


  二分图最大匹配问题,更新了一下$Dinic$模板,带上了当前弧优化和多路增广。这道题输出方案有很多种,可是没有special judge,所以没有A,但方案数是对的。合法的输出方案只能用匈牙利算法解决。

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 1003;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}
queue q;
bool vis[N];
int point[N], cap[N], nxt[N], to[N], d[N], cur[N], S, T, cnt = 1;
bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); d[S] = 0; vis[S] = 1;
	int u, i;
	while (!q.empty()) {
		u = q.front(); q.pop();
		for(i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				vis[to[i]] = 1;
				q.push(to[i]);
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int f, flow = 0;
	for(int &i = cur[u]; i; i = nxt[i])
		if (d[u] + 1 == d[to[i]] && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
int Dinic() {
	int flow = 0, i;
	while (BFS()) {
		for(i = 1; i <= T; ++i) cur[i] = point[i];
		flow += DFS(S, 0x7fffffff);
	}
	return flow;
}
void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}
void findpair(int x) {
	for(int i = point[x]; i; i = nxt[i])
		if (cap[i] == 0 && to[i] != S) {printf("%d %d\n", x, to[i]); break;}
}
int main() {
	int n, m;
	read(n); read(m);
	S = n + m + 1; T = S + 1;
	for(int i = 1; i <= n; ++i)
		ins(S, i, 1), ins(i, S, 0);
	for(int i = n + 1; i <= n + m; ++i)
		ins(i, T, 1), ins(T, i, 0);
	int u, v;
	read(u); read(v);
	while (u != -1 && v != -1) {
		ins(u, v, 1); ins(v, u, 0);
		read(u); read(v);
	}
	printf("%d\n", Dinic());
	for(int i = 1; i <= n; ++i)
		findpair(i);
	return 0;
}

 

2.太空飞行计划问题 2016-04-13


  典型的最大权闭合图问题,可是还是要输出方案!!!制杖地卡了1h+因为把n+m打成了n+m+1,然后发现还是会WA两个点。最后百度得知数据是不盈利也不亏损的项目还要加上,如果要这么做还得删边balabalabala。我不想再改了,所以就这样吧。我现在感觉什么都需要special judge,因为我太弱了hhh

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 1003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

bool vis[N];
queue  q;
int point[N], nxt[N], to[N], cap[N], d[N], cur[N], S, T, cnt = 1, n, m, Qsum = 0, Qmincut;

void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}

bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); vis[S] = 1; d[S] = 0;
	int u, i;
	while (!q.empty()) {
		u = q.front(); q.pop();
		for(i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				q.push(to[i]);
				vis[to[i]] = 1;
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int f, flow = 0;
	for(int &i = cur[u]; i; i = nxt[i])
		if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
int Dinic() {
	int flow = 0, i;
	while (BFS()) {
		for(i = 1; i <= T; ++i) cur[i] = point[i];
		flow += DFS(S, inf);
	}
	return flow;
}

void Q() {
	for(int i = 1; i <= m; ++i)
		if (vis[i]) printf("%d ", i);
	puts("");
	
	for(int i = m + 1; i <= m + n; ++i)
		if (vis[i]) printf("%d ", i - m);
	
	printf("\n%d\n", Qsum - Qmincut);
}

int main() {
	read(m); read(n);
	S = m + n + 1; T = S + 1;
	
	int num; char c;
	for(int i = 1; i <= m; ++i) {
		read(num);
		Qsum += num;
		ins(S, i, num);
		ins(i, S, 0);
		c = getchar();
		while(1) {
			num = 0;
			for(; c < '0' || c > '9'; c = getchar())
				if (c == '\n') break;
			if (c == '\n') break;
			for(; c >= '0' && c <= '9'; c = getchar())
				num = num * 10 + c - '0';
			num = num + m;
			ins(i, num, inf);
			ins(num, i, 0);
		}
	}
	
	for(int i = m + 1; i <= m + n; ++i) {
		read(num);
		ins(i, T, num);
		ins(T, i, 0);
	}
	
	Qmincut = Dinic();
	
	Q();
	
	return 0;
}

 

3.最小路径覆盖问题 2016-04-13


  二分图最大匹配问题。遇到求“最小”,因为我们求的都是最大流,所以应该往补集转化的方向思考,“总的”-“最大的”=“最小的”。这种题还应该注意一个地方,虽然在这里用不着,但要处处留心:最小路径覆盖问题值得注意的地方

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 20003;
const int inf = 0x7fffffff;

queue  q;
bool vis[N];
int point[N], cur[N], nxt[N], to[N], cap[N], d[N], n, m, S, T, cnt = 1, Qmincut;

int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}

bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); d[S] = 0; vis[S] = 1;
	while (!q.empty()) {
		int u = q.front(), i; q.pop();
		for(i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				vis[to[i]] = 1;
				q.push(to[i]);
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int f, flow = 0;
	for(int &i = point[u]; i; i = nxt[i])
		if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
int Dinic() {
	int i, flow = 0;
	while (BFS()) {
		for(i = 1; i <= T; ++i) cur[i] = point[i];
		flow += DFS(S, inf);
	}
	return flow;
}

void QQ(int x) {
	vis[x] = 1;
	printf("%d ", x);
	for(int i = point[x]; i; i = nxt[i])
		if (cap[i] < inf && n < to[i] && to[i] <= n + n) QQ(to[i] - n);
}
void Q() {
	memset(vis, 0, sizeof(vis));
	for(int i = 1; i <= n; ++i)
		if (!vis[i]) QQ(i), puts("");
	printf("%d\n", n - Qmincut);
}
int main() {
	read(n); read(m);
	int u, v;
	S = n + n + 1; T = S + 1;
	for(int i = 1, j = n + 1; i <= n; ++i, ++j)
		ins(S, i, 1), ins(i, S, 0), ins(j, T, 1), ins(T, j, 0);
	for(int i = 1; i <= m; ++i) {
		read(u); read(v); v += n;
		ins(u, v, inf); ins(v, u, 0);
	}
	
	Qmincut = Dinic();
	
	Q();
	
	return 0;
}

 

4.魔术球问题 2016-04-17


  最小路径覆盖问题,想了好久,看完题解后还是想了好久QuQ。当时主要是不明白为什么满足单调性,后来才发现DAG上不断加边,最小路径覆盖数肯定是不减的,当时好制杖啊QAQ。写完后更制杖的是我发现我又需要special judge!!!怎么我现在弱到什么都需要special judge!!!PS:昨天北大先修课乙烷,xyx考得最好但是他没有用正规的比赛号交题,,,

#include
#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 100003;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c= getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], nxt[N << 1], to[N << 1], cap[N << 1], d[N], S, T, cnt = 1, ans = 0, n, Q = 0;
bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				vis[to[i]] = 1;
				q.push(to[i]);
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int f, flow = 0;
	for(int i = point[u]; i; i = nxt[i])
		if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
void Dinic() {
	while (BFS()) ans -= DFS(S, 0x7fffffff);
}

void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}
void Qwork(int x) {
	printf("%d ", x);
	vis[x] = 1;
	for(int i = point[x]; i; i = nxt[i])
		if (!cap[i] &&  to[i] > 5000 && to[i] < 5000 + Q && !vis[to[i] - 5000])
			Qwork(to[i] - 5000);
}
int main() {
	read(n); S = 0; T = 10002;
	while (1) {
		++ans; ++Q;
		for(int i = 1; i < Q; ++i)
			if (sqrt(i + Q) == (int)(sqrt(i + Q)))
				ins(i, Q + 5000, 1), ins(Q + 5000, i, 0);
		ins(S, Q, 1); ins(Q, S, 0);
		ins(Q + 5000, T, 1); ins(T, Q + 5000, 0);
		Dinic();
		if (ans > n) {
			printf("%d\n", Q - 1);
			break;
		}
	}
	
	memset(vis, 0, sizeof(vis));
	for(int i = 1; i < Q; ++i)
		if (!vis[i])
			Qwork(i), puts("");
	
	return 0;
}

 

5.圆桌问题 2016-04-17


  很简单的二分图多重匹配,写完后我发现我又需要special judge了QAQ

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 100003;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], cur[N], nxt[N << 1], to[N << 1], cap[N << 1], S, T, cnt = 1, d[N];

bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				vis[to[i]] = 1;
				q.push(to[i]);
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int f, flow = 0;
	for(int &i = cur[u]; i; i = nxt[i])
		if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
int Dinic() {
	int flow = 0;
	while (BFS()) {
		for(int i = 0; i <= T; ++i) cur[i] = point[i];
		flow += DFS(S, 0x7fffffff);
	}
	return flow;
}

void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}
int main() {
	int n, m, x, Qsum = 0;
	read(m); read(n);
	S = 0; T = m + n + 1;
	for(int i = 1; i <= m; ++i)
		read(x), ins(S, i, x), ins(i, S, 0), Qsum += x;
	for(int i = m + 1; i < T; ++i)
		read(x), ins(i, T, x), ins(T, i, 0);
	for(int i = 1; i <= m; ++i)
		for(int j = m + 1; j < T; ++j)
			ins(i, j, 1), ins(j, i, 0);
	
	int Q = Dinic();
	if (Q == Qsum) {
		puts("1");
		for(int i = 1; i <= m; ++i) {
			cnt = 0;
			for(int tmp = point[i]; tmp; tmp = nxt[tmp])
				if (!cap[tmp] && to[tmp] > m && to[tmp] < T)
					d[++cnt] = to[tmp] - m;
			for(; cnt; --cnt) printf("%d ", d[cnt]);
			puts("");
		}
	} else
		puts("0");
	
	return 0;
}

 

6.最长递增子序列问题 2016-04-17


  分层图思想可以保证走的每条路都是最长的,统计最大流就可以了,对于第三问放宽$X_1,X_n$的限制即可。还有一个地方我卡了好久,就是$inf$设置成了$0x7fffffff$,这样会出现爆int的情况,只需把inf调小一点,输出时特判一下就没了,,,TwT我卡了3h+啊

#include
#include
#include
#include
#define read(x) x = getint()
using namespace std;
const int N = 100003;
const int inf = 1E9;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], cur[N], d[N], nxt[N << 1], to[N << 1], cap[N << 1], S, T, cnt = 1;

bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); d[S] = 0; vis[S] = 1;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				vis[to[i]] = 1;
				q.push(to[i]);
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int f, flow = 0;
	for(int &i = cur[u]; i; i = nxt[i])
		if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
int Dinic() {
	int i, flow = 0;
	while (BFS()) {
		for(i = 0; i <= T; ++i) cur[i] = point[i];
		flow += DFS(S, inf);
	}
	return flow;
}

int a[N], f[N];
void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}
int main() {
	int n;
	read(n);
	for(int i = 1; i <= n; ++i)
		read(a[i]);
	
	f[n] = 1;
	for(int i = n - 1; i > 0; --i) {
		f[i] = 1;
		for(int j = n; j > i; --j)
			if (a[i] <= a[j] && f[j] + 1 > f[i])
				f[i] = f[j] + 1;
	}
	
	int k = 0;
	for(int i = 1; i <= n; ++i)
		k = max(k, f[i]);
	printf("%d\n", k);
	
	S = 0; T = (n << 1) + 1;
	for(int i = 1; i <= n; ++i) {
		ins(i, i + n, 1), ins(i + n, i, 0);
		if (f[i] == k)
			ins(S, i, 1), ins(i, S, 0);
		if (f[i] == 1)
			ins(i + n, T, 1), ins(T, i + n, 0);
	}
	for(int i = 1; i < n; ++i)
		for(int j = i + 1; j <= n; ++j)
			if (a[i] <= a[j] && f[i] == f[j] + 1)
				ins(i + n, j, 1), ins(j, i + n, 0);
	int Q = Dinic();
	printf("%d\n", Q);
	
	memset(point, 0, sizeof(point)); cnt = 1;
	for(int i = 1; i <= n; ++i) {
		if (i == 1 || i == n) {
			ins(i, i + n, inf), ins(i + n, i, 0);
			if (f[i] == k)
				ins(S, i, inf), ins(i, S, 0);
			if (f[i] == 1)
				ins(i + n, T, inf), ins(T, i + n, 0);
		} else {
			ins(i, i + n, 1), ins(i + n, i, 0);
			if (f[i] == k)
				ins(S, i, 1), ins(i, S, 0);
			if (f[i] == 1)
				ins(i + n, T, 1), ins(T, i + n, 0);
		}
	}
	for(int i = 1; i < n; ++i)
		for(int j = i + 1; j <= n; ++j)
			if (a[i] <= a[j] && f[i] == f[j] + 1)
				ins(i + n, j, 1), ins(j, i + n, 0);
	Q = Dinic();
	printf("%d\n", Q > inf ? n : Q);
	
	return 0;
}

 

7.试题库问题 2016-04-17


  水题,不过我又需要special judge了QuQ

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 10003;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], cur[N], nxt[N << 1], to[N << 1], S, T, cnt = 1, d[N], cap[N << 1];

bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); d[S] = 0; vis[S] = 1;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				vis[to[i]] = 1;
				q.push(to[i]);
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int flow = 0, f;
	for(int &i = cur[u]; i; i = nxt[i])
		if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
int Dinic() {
	int flow = 0;
	while (BFS()) {
		for(int i = 0; i <= T; ++i) cur[i] = point[i];
		flow += DFS(S, 0x7fffffff);
	}
	return flow;
}

void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}
int main() {
	int k, n, m = 0, x, p;
	read(k); read(n);
	S = 0; T = k + n + 1;
	for(int i = 1; i <= k; ++i)
		read(x), ins(S, i, x), ins(i, S, 0), m += x;
	for(int i = 1; i <= n; ++i) {
		read(p);
		for(int j = 1; j <= p; ++j) {
			read(x);
			ins(x, i + k, 1);
			ins(i + k, x, 0);
		}
	}
	for(int i = k + 1; i < T; ++i)
		ins(i, T, 1), ins(T, i, 0);
	
	int Q = Dinic();
	if (Q == m) {
		for(int i = 1; i <= k; ++i) {
			printf("%d:", i);
			for(int tmp = point[i]; tmp; tmp = nxt[tmp])
				if (!cap[tmp] && to[tmp] > k && to[tmp] < T)
					printf(" %d", to[tmp] - k);
			puts("");
		}
	} else
		puts("No Solution!");
	
	return 0;
}

 

8.机器人路径规划问题


  貌似这道题挺麻烦,CTSC和省选Round2前没有太多时间,暂时略过,省选二轮滚粗后再来看QAQ

 

9.方格取数问题 2016-04-18


  因为最大独立点集+最小点覆盖集=总点数,那么最大点权独立集+最小点权覆盖集=总点权和。我们只需求最小点权覆盖集就可以了。

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int inf = 0x7fffffff;
const int N = 100003;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], cur[N], nxt[N << 1], cap[N << 1], to[N << 1], S, T, cnt = 1, d[N];

bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				vis[to[i]] = 1;
				q.push(to[i]);
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int flow = 0, f;
	for(int &i = cur[u]; i; i = nxt[i])
		if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
int Dinic() {
	int flow = 0;
	while (BFS()) {
		for(int i = 0; i <= T; ++i) cur[i] = point[i];
		flow += DFS(S, inf);
	}
	return flow;
}

int a[53][53];
void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}
void QQ(int Qsum) {
	int Q = Dinic();
	Q = Qsum - Q;
	printf("%d\n", Q);
}
int main() {
	int n, m, Qsum = 0;
	read(m); read(n);
	for(int i = 1; i <= m; ++i)
		for(int j = 1; j <= n; ++j)
			read(a[i][j]), Qsum += a[i][j];
	S = 0; T = n * m + 1;
	for(int i = 1; i <= m; ++i)
		for(int j = 1; j <= n; ++j)
			if ((i + j) % 2 == 0) {
				ins(S, (i - 1) * n + j, a[i][j]);
				ins((i - 1) * m + j, S, 0);
				if (i > 1) {
					ins((i - 1) * n + j, (i - 2) * n + j, inf);
					ins((i - 2) * n + j, (i - 1) * n + j, 0);
				}
				if (j > 1) {
					ins((i - 1) * n + j, (i - 1) * n + j - 1, inf);
					ins((i - 1) * n + j - 1, (i - 1) * n + j, 0);
				}
				if (i < m) {
					ins((i - 1) * n + j, i * n + j, inf);
					ins(i * n + j, (i - 1) * n + j, 0);
				}
				if (j < n) {
					ins((i - 1) * n + j, (i - 1) * n + j + 1, inf);
					ins((i - 1) * n + j + 1, (i - 1) * n + j, 0);
				}
			}
	for(int i = 1; i <= m; ++i)
		for(int j = 1; j <= n; ++j)
			if ((i + j) % 2 == 1) {
				ins((i - 1) * n + j, T, a[i][j]);
				ins(T, (i - 1) * n + j, 0);
			}
	
	QQ(Qsum);
	
	return 0;
}

 

10.餐巾计划问题 2016-04-18


  最小费用最大流问题。在保证最大流的前提下求最小费用,建图我就不细说了,主要是把买的和洗的餐巾分为两部分,网上有很多题解。

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 100003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], nxt[N << 1], to[N << 1], cap[N << 1], S, T, cnt = 1;
int d[N], w[N << 1], from[N << 1], pre[N << 1];

bool spfa(int s, int t) {
	for(int i = 0; i <= t; ++i) vis[i] = 0, d[i] = inf;
	d[s] = 0; q.push(s);
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for(int i = point[u]; i; i = nxt[i])
			if (cap[i] && d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				pre[to[i]] = i;
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	return d[t] != inf;
}
int mcmf(int s, int t) {
	int ret = 0, f, u;
	while (spfa(s, t)) {
		f = inf;
		for(u = t; u != s; u = from[pre[u]]) f = min(f, cap[pre[u]]);
		for(u = t; u != s; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f;
		ret += f * d[t];
	}
	return ret;
}

int nn, p, m, f, n, s, r[N];
void ins(int x, int y, int z, int zz) {
	nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt;
}
int main() {
	read(nn); read(p); read(m); read(f); read(n); read(s);
	for(int i = 1; i <= nn; ++i)
		read(r[i]);
	S = 0; T = (nn << 1) + 1;
	for(int i = 1; i <= nn; ++i) {
		ins(S, i, r[i], 0);
		ins(i, S, 0, 0);
		ins(i + nn, T, r[i], 0);
		ins(T, i + nn, 0, 0);
		ins(S, i + nn, inf, p);
		ins(i + nn, S, 0, -p);
		if (i < nn) {
			ins(i, i + 1, inf, 0);
			ins(i + 1, i, 0, 0);
		}
		if (i + m <= nn) {
			ins(i, i + m + nn, inf, f);
			ins(i + m + nn, i, 0, -f);
		}
		if (i + n <= nn) {
			ins(i, i + n + nn, inf, s);
			ins(i + n + nn, i, 0, -s);
		}
	}
	
	int Q = mcmf(S, T);
	printf("%d\n", Q);
	
	return 0;
}

 

11.航空路线问题 2016-04-18


  裸拆点最小费用最大流,我打错了MCMF模板,查了1h的错TwT。在第二组数据吐血QAQ,只好面向数据编程,,,还有I need special judge again!!!

#include
#include
#include
#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 100003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

map  ma;
queue  q;
bool vis[N];
int point[N], nxt[N << 1], to[N << 1], cap[N << 1], d[N];
int S, T, cnt = 1, w[N << 1], from[N << 1], pre[N];

bool spfa() {
	for(int i = 0; i <= T; ++i) vis[i] = 0, d[i] = inf;
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for(int i = point[u]; i; i = nxt[i])
			if (cap[i] && d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				pre[to[i]] = i;
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	return d[T] != inf;
}
int mcmf() {
	int ret = 0, f, u;
	while (spfa()) {
		f = inf;
		for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]);
		for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f;
		ret += f * d[T];
	}
	return ret;
}

int n, v, x, y;
string s1, s2, str[N];
void ins(int x, int y, int z, int zz) {
	nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt;
}
void QQ(int x) {
	cout<< str[x] << endl;
	for(int i = point[x + n]; i; i = nxt[i])
		if (!cap[i] && !vis[to[i]] && to[i] > 0 && to[i] <= n)
			{QQ(to[i]); break;}
}
void QQQ(int x) {
	if (x == n) {
		QQ(1);
		return;
	}
	vis[x] = 1;
	for(int i = point[x + n]; i; i = nxt[i])
		if (!cap[i] && to[i] > 0 && to[i] <= n)
			{QQQ(to[i]); break;}
	cout << str[x] <> str[i], ma[str[i]] = i;
	S = 1; T = n << 1;
	for(int i = 1; i <= n; ++i)
		if (i == 1 || i == n) {
			ins(i, i + n, 2, -1);
			ins(i + n, i, 0, 1);
		} else {
			ins(i, i + n, 1, -1);
			ins(i + n, i, 0, 1);
		}
	for(int i = 1; i <= v; ++i) {
		cin >> s1 >> s2;
		x = ma[s1]; y = ma[s2];
		ins(x + n, y, 1, 0);
		ins(y, x + n, 0, 0);
	}
	
	int Q = mcmf();
	if (cap[2] && n != 3)
		puts("No Solution!");
	else
		printf("%d\n", n != 3 ? - Q - 2 : -Q), memset(vis, 0, sizeof(vis)), QQQ(1);
	
	return 0;
}

 

12.软件补丁问题 2016-04-18


  因为只有20种错误,考虑状态压缩然后spfa最短路,这还是网络流吗,,,

#include
#include
#include
#include
using namespace std;
const int N = 2000003;
char a[23], b[23];
bool vis[N];
queue  q;
int b1[N], b2[N], f1[N], f2[N], cost[N], n, m, d[N], inf;
int spfa(int s, int t) {
	memset(d, 127, sizeof(d)); inf = d[t];
	d[s] = 0; q.push(s); vis[s] = 0;
	
	while (!q.empty()) {
		int x = q.front(); q.pop(); vis[x] = 0;
		for(int i = 1; i <= m; ++i)
			if ((x | b1[i]) == x && (x & b2[i]) == 0) {
				int y = x & (~ f1[i]);
				y |= f2[i];
				if (d[y] > d[x] + cost[i]) {
					d[y] = d[x] + cost[i];
					if (!vis[y]) {
						vis[y] = 1; 
						q.push(y);
					}
				}
			}
	}
	
	return d[t] == inf ? 0 : d[t];
}

int main() {
	memset(b1, 0, sizeof(b1));
	memset(b2, 0, sizeof(b2));
	memset(f1, 0, sizeof(f1));
	memset(f2, 0, sizeof(f2));
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; ++i) {
		scanf("%d %s %s", &cost[i], a, b);
		for(int j = 0; j < strlen(a); ++j)
			if (a[j] == '+') b1[i] |= 1 << j;
			else if (a[j] == '-') b2[i] |= 1 << j;
		for(int j = 0; j < strlen(b); ++j)
			if (b[j] == '+') f2[i] |= 1 << j;
			else if (b[j] == '-') f1[i] |= 1 << j;
	}
	
	printf("%d\n", spfa((1 << n) - 1, 0));
	
	return 0;
}

 

13.星际转移问题 2016-04-18


  将每天转化为分层图,然后每天都跑最大流,若最大流大于等于k,则输出答案。特殊情况我还是面向数据编程,,,我怎么这么弱QAQ

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 2000003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

bool vis[N];
queue  q;
int point[N], cur[N], nxt[N], cap[N], d[N], to[N], S, T, cnt = 1;

bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				vis[to[i]] = 1;
				q.push(to[i]);
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int flow = 0, f;
	for(int &i = cur[u]; i; i = nxt[i])
		if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
int Dinic() {
	int flow = 0;
	while (BFS()) {
		for(int i = 0; i <= T; ++i) cur[i] = point[i];
		flow += DFS(S, inf);
	}
	return flow;
}

struct node {int r, num, a[103];} B[203];
int n, m, k;
void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}
void mk(int &x) {x = (x == 0 ? n + 1 : (x == -1 ? n + 2 : x));}
int main() {
	read(n); read(m); read(k);
	S = 0; T = N - 3;
	for(int i = 1; i <= m; ++i) {
		read(B[i].r); read(B[i].num);
		for(int j = 1; j <= B[i].num; ++j)
			read(B[i].a[j]), mk(B[i].a[j]);
		B[i].a[0] = B[i].a[B[i].num];
	}
	int earth = n + 1, moon = n + 2, gh = moon, Q = 0;
	
	ins(S, earth, k), ins(earth, S, 0);
	for(int Day = 1; Day <= 30; ++Day) {
		for(int i = 1; i < gh; ++i) {
			ins((Day - 1) * gh + i, Day * gh + i, inf);
			ins(Day * gh + i, (Day - 1) * gh + i, 0);
		}
		ins(Day * gh + moon, T, inf), ins(T, Day * gh + moon, 0);
		for(int i = 1; i <= m; ++i) {
			int last = B[i].a[Day % B[i].num], now = B[i].a[(Day + 1) % B[i].num];
			ins((Day - 1) * gh + last, Day * gh + now, B[i].r);
			ins(Day * gh + now, (Day - 1) * gh + last, 0);
		}
		Q += Dinic();
		if (Q >= k) {
			printf("%d\n", Day);
			break;
		}
	}
	
	if (Q < k)
		puts("0");
	
	return 0;
}

 

14.孤岛营救问题 2016-04-18


  在分层图上spfa,不是网络流,,,以后是不是遇到水的数据就应该考虑不同寻常的做法。

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 2000003;
const int inf = 2139062143;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int cnt = 1, point[N], nxt[N], to[N], w[N], d[N];

void spfa(int s) {
	memset(vis, 0, sizeof(vis));
	memset(d, 127, sizeof(d));
	q.push(s); vis[s] = 1; d[s] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for(int i = point[u]; i; i = nxt[i])
			if (d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
}

int n, m, p, k, S, map[16][16][16][16];
void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; w[cnt] = z; point[x] = cnt;
}
int main() {
	read(n); read(m); read(p); read(k);
	memset(map, -1, sizeof(map));
	int x1, x2, y1, y2, z, dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
	for(int i = 1; i <= k; ++i) {
		read(x1); read(y1); read(x2); read(y2); read(z);
		map[x1][y1][x2][y2] = map[x2][y2][x1][y1] = z;
	}
	
	read(S);
	for(int i = 1; i <= S; ++i) {
		read(x1); read(y1); read(z);
		for(int j = 0; j < (1 << p); ++j)
			if (((1 << (z - 1)) & j) == 0)
				ins(j * n * m + (x1 - 1) * m + y1, (j | (1 << (z - 1))) * n * m + (x1 - 1) * m + y1, 0);
	}
	
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m; ++j)
			for(int nu = 0; nu < 4; ++nu) {
				x1 = i + dx[nu]; y1 = j + dy[nu];
				if (x1 > 0 && x1 <= n && y1 > 0 && y1 <= m) {
					if (map[i][j][x1][y1] == -1) {
						for(int l = 0; l < (1 << p); ++l)
							ins(l * n * m + (i - 1) * m + j, l * m * n + (x1 - 1) * m + y1, 1);
					} else if (map[i][j][x1][y1] > 0) {
						for(int l = 0; l < (1 << p); ++l)
							if ((1 << (map[i][j][x1][y1] - 1)) & l)
								ins(l * n * m + (i - 1) * m + j, l * n * m + (x1 -1) * m + y1, 1);
					}
				}
			}
	
	spfa(1);
	int Q = inf;
	for(int i = 0; i <= (1 << p); ++i)
		Q = min(Q, d[i * n * m]);
	printf("%d\n", Q == inf ? -1 : Q);
	
	return 0;
}

 

15.汽车加油形式问题 2016-04-18


  还是最短路,,,BFS暴力过掉,不知道还有什么其他做法。

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

struct node {int x, y, gas, cos;};
queue  q;
int N, K, A, B, C, f[103][103][13], dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
short a[103][103];

int Q() {
	node u, now;
	memset(f, 127, sizeof(f));
	f[1][1][K] = 0;
	u.x = u.y = 1; u.gas = K; u.cos = 0;
	q.push(u);
	while (!q.empty()) {
		u = q.front(); q.pop();
		if (u.gas == 0) continue;
		for(int i = 0; i < 4; ++i) {
			now.x = u.x + dx[i]; now.y = u.y + dy[i];
			if (now.x > 0 && now.x <= N && now.y > 0 && now.y <= N) {
				now.gas = u.gas - 1; now.cos = u.cos;
				if (now.x < u.x || now.y < u.y)
					now.cos += B;
				if (a[now.x][now.y]) {
					now.gas = K; now.cos += A;
					if (now.cos < f[now.x][now.y][now.gas])
						f[now.x][now.y][now.gas] = now.cos, q.push(now);
				} else {
					if (now.cos < f[now.x][now.y][now.gas])
						f[now.x][now.y][now.gas] = now.cos, q.push(now);
					now.gas = K; now.cos += A + C;
					if (now.cos < f[now.x][now.y][now.gas])
						f[now.x][now.y][now.gas] = now.cos, q.push(now);
				}
			}
		}
	}
	
	int ret = 0x7fffffff;
	for(int i = 0; i <= K; ++i)
		ret = min(ret, f[N][N][i]);
	return ret;
}

int main() {
	read(N); read(K); read(A); read(B); read(C);
	for(int i = 1; i <= N; ++i)
		for(int j = 1; j <= N; ++j)
			read(a[i][j]);
	
	printf("%d\n", Q());
	
	return 0;
}

 

16.数字梯形问题 2016-04-18


  最小费用最大流,相当于写了3道水题,不过Ctrl+C,Ctrl+V大法好!建图时结点直接用坐标表示略偷懒

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 100003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], nxt[N], to[N], pre[N], from[N], cap[N], d[N], w[N], S, T, cnt = 1;

bool spfa() {
	for(int i = 0; i <= T; ++i) vis[i] = 0, d[i] = inf;
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for(int i = point[u]; i; i = nxt[i])
			if (cap[i] && d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				pre[to[i]] = i;
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	return d[T] != inf;
}
int mcmf() {
	int ret = 0, f, u;
	while (spfa()) {
		f = inf;
		for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]);
		for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f;
		ret += f * d[T];
	}
	return ret;
}

int m, n, ss, nn, x[103][103];
void ins(int x, int y, int z, int zz) {
	nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt;
}
int main() {
	read(m); read(n);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m + i - 1; ++j)
			read(x[i][j]);
	
	nn = (m + n) * n; T = 2 * nn + 2; ss = T - 1; S = 0;
	ins(S, ss, m, 0); ins(ss, S, 0, 0);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m + i - 1; ++j) {
			ins((i - 1) * (n + m) + j, (i - 1) * (n + m) + j + nn, 1, - x[i][j]);
			ins((i - 1) * (n + m) + j + nn, (i - 1) * (n + m) + j, 0, x[i][j]);
			if (i == n) {
				ins((i - 1) * (n + m) + j + nn, T, 1, 0);
				ins(T, (i - 1) * (n + m) + j + nn, 0, 0);
			} else {
				if (i == 1) {
					ins(ss, (i - 1) * (n + m) + j, 1, 0);
					ins((i - 1) * (n + m) + j, ss, 0, 0);
				}
				ins((i - 1) * (n + m) + j + nn, i * (n + m) + j, 1, 0);
				ins(i * (n + m) + j, (i - 1) * (n + m) + j + nn, 0, 0);
				ins((i - 1) * (n + m) + j + nn, i * (n + m) + j + 1, 1, 0);
				ins(i * (n + m) + j + 1, (i - 1) * (n + m) + j + nn, 0, 0);
			}
		}
	int Q = mcmf();
	printf("%d\n", - Q);
	
	memset(point, 0, sizeof(point));
	ins(S, ss, m, 0); ins(ss, S, 0, 0);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m + i - 1; ++j) {
			ins((i - 1) * (n + m) + j, (i - 1) * (n + m) + j + nn, inf, - x[i][j]);
			ins((i - 1) * (n + m) + j + nn, (i - 1) * (n + m) + j, 0, x[i][j]);
			if (i == n) {
				ins((i - 1) * (n + m) + j + nn, T, inf, 0);
				ins(T, (i - 1) * (n + m) + j + nn, 0, 0);
			} else {
				if (i == 1) {
					ins(ss, (i - 1) * (n + m) + j, 1, 0);
					ins((i - 1) * (n + m) + j, ss, 0, 0);
				}
				ins((i - 1) * (n + m) + j + nn, i * (n + m) + j, 1, 0);
				ins(i * (n + m) + j, (i - 1) * (n + m) + j + nn, 0, 0);
				ins((i - 1) * (n + m) + j + nn, i * (n + m) + j + 1, 1, 0);
				ins(i * (n + m) + j + 1, (i - 1) * (n + m) + j + nn, 0, 0);
			}
		}
	Q = mcmf();
	printf("%d\n", - Q);
	
	memset(point, 0, sizeof(point));
	ins(S, ss, m, 0); ins(ss, S, 0, 0);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= m + i - 1; ++j) {
			ins((i - 1) * (n + m) + j, (i - 1) * (n + m) + j + nn, inf, - x[i][j]);
			ins((i - 1) * (n + m) + j + nn, (i - 1) * (n + m) + j, 0, x[i][j]);
			if (i == n) {
				ins((i - 1) * (n + m) + j + nn, T, inf, 0);
				ins(T, (i - 1) * (n + m) + j + nn, 0, 0);
			} else {
				if (i == 1) {
					ins(ss, (i - 1) * (n + m) + j, 1, 0);
					ins((i - 1) * (n + m) + j, ss, 0, 0);
				}
				ins((i - 1) * (n + m) + j + nn, i * (n + m) + j, inf, 0);
				ins(i * (n + m) + j, (i - 1) * (n + m) + j + nn, 0, 0);
				ins((i - 1) * (n + m) + j + nn, i * (n + m) + j + 1, inf, 0);
				ins(i * (n + m) + j + 1, (i - 1) * (n + m) + j + nn, 0, 0);
			}
		}
	Q = mcmf();
	printf("%d\n", - Q);
	
	return 0;
}

 

17.运输问题 2016-04-19


  最小费用最大流,,,

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 100003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], nxt[N], cap[N], from[N], w[N], to[N], d[N], pre[N], S, T, cnt = 1;

bool spfa() {
	for(int i = 1; i <= T; ++i) vis[i] = 0, d[i] = inf;
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for(int i = point[u]; i; i = nxt[i])
			if (cap[i] && d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				pre[to[i]] = i;
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	return d[T] != inf;
}
int mcmf() {
	int ret = 0, f, u;
	while (spfa()) {
		f = inf;
		for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]);
		for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f;
		ret += f * d[T];
	}
	return ret;
}

int m, n, x[503], c[503][503];
void ins(int x, int y, int z, int zz) {
	nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt;
}
int main() {
	read(m); read(n);
	S = 0; T = m + n + 1;
	for(int i = 1; i <= m; ++i)
		read(x[i]), ins(S, i, x[i], 0), ins(i, S, 0, 0);
	for(int i = m + 1; i < T; ++i)
		read(x[i]), ins(i, T, x[i], 0), ins(T, i, 0, 0);
	for(int i = 1; i <= m; ++i)
		for(int j = m + 1; j < T; ++j) {
			read(c[i][j]);
			ins(i, j, inf, c[i][j]);
			ins(j, i, 0, - c[i][j]);
		}
	int Q = mcmf();
	printf("%d\n", Q);
	
	memset(point, 0, sizeof(point)); cnt = 1;
	for(int i = 1; i <= m; ++i)
		ins(S, i, x[i], 0), ins(i, S, 0, 0);
	for(int i = m + 1; i < T; ++i)
		ins(i, T, x[i], 0), ins(T, i, 0, 0);
	for(int i = 1; i <= m; ++i)
		for(int j = m + 1; j < T; ++j) {
			ins(i, j, inf, - c[i][j]);
			ins(j, i, 0, c[i][j]);
		}
	Q = - mcmf();
	printf("%d\n", Q);
	
	return 0;
}

 

18.分配问题 2016-04-19


  最小费用最大流,,,,,,,,,,,,,,,,,

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 100003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], nxt[N], cap[N], from[N], w[N], to[N], d[N], pre[N], S, T, cnt = 1;

bool spfa() {
	for(int i = 1; i <= T; ++i) vis[i] = 0, d[i] = inf;
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for(int i = point[u]; i; i = nxt[i])
			if (cap[i] && d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				pre[to[i]] = i;
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	return d[T] != inf;
}
int mcmf() {
	int ret = 0, f, u;
	while (spfa()) {
		f = inf;
		for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]);
		for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f;
		ret += f * d[T];
	}
	return ret;
}

int n, c[503][503];
void ins(int x, int y, int z, int zz) {
	nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt;
}
int main() {
	read(n);
	S = 0; T = n + n + 1;
	for(int i = 1; i <= n; ++i)
		ins(S, i, 1, 0), ins(i, S, 0, 0);
	for(int i = n + 1; i < T; ++i)
		ins(i, T, 1, 0), ins(T, i, 0, 0);
	for(int i = 1; i <= n; ++i)
		for(int j = n + 1; j < T; ++j) {
			read(c[i][j]);
			ins(i, j, inf, c[i][j]);
			ins(j, i, 0, - c[i][j]);
		}
	int Q = mcmf();
	printf("%d\n", Q);
	
	memset(point, 0, sizeof(point)); cnt = 1;
	for(int i = 1; i <= n; ++i)
		ins(S, i, 1, 0), ins(i, S, 0, 0);
	for(int i = n + 1; i < T; ++i)
		ins(i, T, 1, 0), ins(T, i, 0, 0);
	for(int i = 1; i <= n; ++i)
		for(int j = n + 1; j < T; ++j) {
			ins(i, j, inf, - c[i][j]);
			ins(j, i, 0, c[i][j]);
		}
	Q = - mcmf();
	printf("%d\n", Q);
	
	return 0;
}

 

19.负载平衡问题 2016-04-19


  还是最小费用最大流,我第一次WA了,因为只是将$X_i$连了一条向$Y_i$的流量无穷大的边,但有可能出现一些货物运输跨过几个仓库的情况,于是便从$Y_i$向$X_i$连一流量无穷大的边,保证货物在运输一次之后可以继续运输。

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 10003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], nxt[N], from[N], to[N], pre[N], cap[N], w[N], d[N], S, T, cnt = 1;

bool spfa() {
	for(int i = 1; i <= T; ++i) vis[i] = 0, d[i] = inf;
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for(int i = point[u]; i; i = nxt[i])
			if (cap[i] && d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				pre[to[i]] = i;
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	return d[T] != inf;
}
int mcmf() {
	int ret = 0, f, u;
	while (spfa()) {
		f = inf;
		for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]);
		for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f;
		ret += f * d[T];
	}
	return ret;
}

int n, x, Qsum = 0, to1, to2;
void ins(int x, int y, int z, int zz) {
	nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt;
}
int main() {
	read(n);
	S = 0; T = (n << 1) + 1;
	for(int i = 1; i <= n; ++i)
		read(x), ins(S, i, x, 0), ins(i, S, 0, 0), Qsum += x;
	for(int i = n + 1; i < T; ++i)
		ins(i, T, Qsum / n, 0), ins(T, i, 0, 0);
	for(int i = 1; i <= n; ++i) {
		ins(i, i + n, inf / 2, 0);
		ins(i + n, i, inf / 2, 0);
		to1 = i == 1 ? n + n : i - 1 + n;
		to2 = i == n ? 1 + n : i + 1 + n;
		ins(i, to1, inf, 1);
		ins(to1, i, 0, -1);
		ins(i, to2, inf, 1);
		ins(to2, i, 0, -1);
	}
	
	int Q = mcmf();
	printf("%d\n", Q);
	
	return 0;
}

 

20.深海机器人问题 2016-04-19


  BYVoid的题解上说是线性规划网络优化,可是我并没有看出来线性规划用在哪里了,,,这道题建图时因为一条道路上的生物只能采集一次,所以得设流量限制为1,但因为在这条路上采集后其他机器人还可以再走,所以再连一条容量为无穷,费用为0的边,保证了后来的任何机器人都可以从这条路上走过而且不会计算费用233。

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 100003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], from[N], nxt[N], to[N], cap[N], d[N], pre[N], w[N], S, T, cnt = 1;

bool spfa() {
	for(int i = 0; i <= T; ++i) vis[i] = 0, d[i] = inf;
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for(int i = point[u]; i; i = nxt[i])
			if (cap[i] && d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				pre[to[i]] = i;
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	return d[T] != inf;
}
int mcmf() {
	int ret = 0, f, u;
	while (spfa()) {
		f = inf;
		for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]);
		for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f;
		ret += d[T] * f;
	}
	return ret;
}

int P, Q, a, b, r, x, y;
void ins(int x, int y, int z, int zz) {
	nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt;
}
int main() {
	read(a); read(b); read(P); read(Q);
	S = (P + 1) * (Q + 1) + 1; T = S + 1;
	for(int i = 0; i <= P; ++i)
		for(int j = 0; j < Q; ++j) {
			read(x);
			ins(i * (Q + 1) + j, i * (Q + 1) + j + 1, 1, - x);
			ins(i * (Q + 1) + j + 1, i * (Q + 1) + j, 0, x);
			ins(i * (Q + 1) + j, i * (Q + 1) + j + 1, inf, 0);
			ins(i * (Q + 1) + j + 1, i * (Q + 1) + j, 0, 0);
		}
	for(int j = 0; j <= Q; ++j)
		for(int i = 0; i < P; ++i) {
			read(x);
			ins(i * (Q + 1) + j, (i + 1) * (Q + 1) + j, 1, - x);
			ins((i + 1) * (Q + 1) + j, i * (Q + 1) + j, 0, x);
			ins(i * (Q + 1) + j, (i + 1) * (Q + 1) + j, inf, 0);
			ins((i + 1) * (Q + 1) + j, i * (Q + 1) + j, 0, 0);
		}
	for(int i = 1; i <= a; ++i) {
		read(r); read(x); read(y);
		ins(S, x * (Q + 1) + y, r, 0);
		ins(x * (Q + 1) + y, S, 0, 0);
	}
	for(int i = 1; i <= b; ++i) {
		read(r); read(x); read(y);
		ins(x * (Q + 1) + y, T, r, 0);
		ins(T, x * (Q + 1) + y, 0, 0);
	}
	
	int QQ = - mcmf();
	printf("%d\n", QQ);
	
	return 0;
}

 

21.最长k可重区间集问题 2016-04-19


  查了3h错,因为离散化完全写错了,还有这道题数据辣么水,为什么要写离散化(┙>∧<)┙へ┻┻。重写了离散化之后还是WA三个点,又查了1h+后在codevs的题解上发现数据错了(゚皿゚メ)

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 100003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], from[N], nxt[N], to[N], cap[N], w[N], d[N], pre[N], S, T, cnt = 1;

bool spfa() {
	for(int i = 1; i <= T; ++i) vis[i] = 0, d[i] = inf;
	q.push(S); vis[S] = 0; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop(); vis[u] = 0;
		for(int i = point[u]; i; i = nxt[i])
			if (cap[i] && d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				pre[to[i]] = i;
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	return d[T] != inf;
}
int mcmf() {
	int ret = 0, f, u;
	while (spfa()) {
		f = inf;
		for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]);
		for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f;
		ret += f * d[T];
	}
	return ret;
}

struct node {
	int l, r;
} a[1003];
int n, k, H[2003], id[2003], HH[2003], num = 1, cos, He[2003];
bool cmp2(int X, int Y) {return H[X] < H[Y];}
void ins(int x, int y, int z, int zz) {
	nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt;
}
int main() {
	read(n); read(k);
	for(int i = 1; i <= n; ++i)
		read(H[(i << 1) - 1]), read(H[i << 1]);
	for(int i = 1; i <= (n << 1); ++i)
		id[i] = i;
	sort(id + 1, id + (n << 1) + 1, cmp2);
	for(int i = 1; i <= (n << 1); ++i) {
		He[num] = H[id[i]];
		HH[id[i]] = num;
		if (H[id[i]] != H[id[i + 1]] && i != (n << 1)) ++num;
	}
	
	S = 0; T = num + 1;
	ins(S, 1, k, 0); ins(1, S, 0, 0);
	ins(num, T, k, 0); ins(T, num, 0, 0);
	for(int i = 1; i < num; ++i)
		ins(i, i + 1, inf, 0), ins(i + 1, i, 0, 0);
	for(int i = 1; i < (n << 1); i += 2) {
		cos = He[HH[i + 1]] - He[HH[i]];
		ins(HH[i], HH[i + 1], 1, - cos);
		ins(HH[i + 1], H[i], 0, cos);
		printf("%d %d : %d\n", HH[i], HH[i + 1], cos);
	}
	
	int Q = - mcmf();
	printf("%d\n", Q);
	
	return 0;
}

 

22.最长k可重线段集问题 2016-04-19


  查错查了一个下午,发现各大OJ上此题AC率都是0,最后Menci神犇说数据有误,,,不管对不对,我还是先把自己愚蠢的代码贴上来吧

#include
#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const long long N = 1000003;
const long long inf = 0x7fffffff;
long long getint() {
	long long k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
long long point[N], from[N], nxt[N], to[N], cap[N], d[N], w[N], pre[N], S, T, cnt = 1;

bool spfa() {
	for(long long i = 0; i <= T; ++i) vis[i] = 0, d[i] = inf;
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		long long u = q.front(); q.pop(); vis[u] = 0;
		for(long long i = point[u]; i; i = nxt[i])
			if (cap[i] && d[to[i]] > d[u] + w[i]) {
				d[to[i]] = d[u] + w[i];
				pre[to[i]] = i;
				if (!vis[to[i]]) {
					vis[to[i]] = 1;
					q.push(to[i]);
				}
			}
	}
	return d[T] != inf;
}
long long mcmf() {
	long long ret = 0, f, u;
	while (spfa()) {
		f = inf;
		for(u = T; u != S; u = from[pre[u]]) f = min(f, cap[pre[u]]);
		for(u = T; u != S; u = from[pre[u]]) cap[pre[u]] -= f, cap[pre[u] ^ 1] += f;
		ret += d[T] * f;
	}
	return ret;
}

long long n, k, num = 1, W[1003], H[2003], id[2003], HH[2003];
void ins(long long x, long long y, long long z, long long zz) {
	nxt[++cnt] = point[x]; from[cnt] = x; to[cnt] = y; cap[cnt] = z; w[cnt] = zz; point[x] = cnt;
}
long long sqr(long long x) {return x * x;}
bool cmp(long long X, long long Y) {return H[X] < H[Y];}
int main() {
	long long x1, x2, y1, y2;
	read(n); read(k);
	for(long long i = 1; i <= n; ++i) {
		read(x1); read(y1); read(x2); read(y2);
		if (x1 > x2) swap(x1, x2), swap(y1, y2);
		H[(i << 1) - 1] = x1; H[i << 1] = x2;
		W[i] = floor(sqrt(sqr(x1 - x2) + sqr(y1 - y2)));
	}
	for(long long i = 1; i <= (n << 1); ++i)
		id[i] = i;
	sort(id + 1, id + (n << 1) + 1, cmp);
	for(long long i = 1; i <= (n << 1); ++i) {
		HH[id[i]] = num;
		if (H[id[i]] != H[id[i + 1]] && i != (n << 1)) ++num;
	}
	S = 0; T = (num << 1) + 1;
	ins(S, 1, k, 0); ins(1, S, 0, 0);
	ins(num << 1, T, k, 0); ins(T, num << 1, 0, 0);
	for(long long i = 1; i < (num << 1); ++i)
		ins(i, i + 1, inf, 0), ins(i + 1, i, 0, 0);
	for(long long i = 1; i <= n; ++i) {
		long long le = HH[(i << 1) - 1], ri = HH[i << 1];
		if (le == ri) {
			ins((le << 1) - 1, le << 1, 1, - W[i]);
			ins(le << 1, (le << 1) - 1, 0, W[i]);
		} else {
			ins(le << 1, (ri << 1) - 1, 1, - W[i]);
			ins((ri << 1) - 1, le << 1, 0, W[i]);	
		}
	}
	
	long long Q = - mcmf();
	printf("%d\n", Q);
	
	return 0;
}

 

23.火星探险问题 2016-04-19


  数据还是有问题!!!和深海机器人问题差不多,我就不做了吧,,,毕竟A不了

 

24.骑士共存问题 2016-04-19


  典型最大权闭合图,染色后建图,,,zyf神犇说这是道水题←此话没有特别意思

#include
#include
#include
#include
#define read(x) x=getint()
using namespace std;
const int N = 1000003;
const int inf = 0x7fffffff;
int getint() {
	int k = 0, fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = k * 10 + c - '0';
	return k * fh;
}

queue  q;
bool vis[N];
int point[N], cur[N], d[N], cap[N], nxt[N], to[N], S, T, cnt = 1;

bool BFS() {
	memset(vis, 0, sizeof(vis));
	q.push(S); vis[S] = 1; d[S] = 0;
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = point[u]; i; i = nxt[i])
			if (!vis[to[i]] && cap[i]) {
				d[to[i]] = d[u] + 1;
				vis[to[i]] = 1;
				q.push(to[i]);
			}
	}
	return vis[T];
}
int DFS(int u, int a) {
	if (u == T || !a) return a;
	int flow = 0, f;
	for(int &i = cur[u]; i; i = nxt[i])	
		if (d[to[i]] == d[u] + 1 && (f = DFS(to[i], min(a, cap[i]))) > 0) {
			flow += f; a -= f; cap[i] -= f; cap[i ^ 1] += f;
			if (!a) break;
		}
	return flow;
}
int Dinic() {
	int flow = 0, i;
	while (BFS()) {
		for(i = 0; i <= T; ++i) cur[i] = point[i];
		flow += DFS(S, inf);
	}
	return flow;
}

bool pd[203][203];
int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}, dy[8] = {2, 1, -1, -2, -2, -1, 1, 2};
int n, m, x, y;
void ins(int x, int y, int z) {
	nxt[++cnt] = point[x]; to[cnt] = y; cap[cnt] = z; point[x] = cnt;
}
int main() {
	read(n); read(m);
	for(int i = 1; i <= m; ++i) {
		read(x); read(y);
		pd[x][y] = 1;
	}
	S = 0; T = n * n + 1;
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			if (!pd[i][j])
				if ((i + j) % 2 ==0) {
					ins(S, (i - 1) * n + j, 1);
					ins((i - 1) * n + j, S, 0);
				} else {
					ins((i - 1) * n + j, T, 1);
					ins(T, (i - 1) * n + j, 0);
				}
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			if (!pd[i][j] && (i + j) % 2 == 0)
				for(int k = 0; k < 8; ++k) {
					x = i + dx[k]; y = j + dy[k];
					if (x < 1 || x > n || y < 1 || y > n || pd[x][y])
						continue;
					int now = (x - 1) * n + y;
					ins((i - 1) * n + j, now, inf);
					ins(now, (i - 1) * n + j, 0);
				}
	
	int Q = Dinic();
	printf("%d\n", n * n - m - Q);
	
	return 0;
}

 


2016-04-19:线性规划与网络流24题就告一段落了,因为8机器人路径规划问题有点困难,暂时先放一放,还有最长k可重线段集问题和火星探险问题2道题的测试数据存在较大问题,没有办法AC,所以那三道题就先被我抛弃了QAQ。说好的线性规划呢?做完了连线性规划的影子都没见到,还是我太弱根本不懂线性规划QuQ。今天是停课第二天,我有没有取得进步自己也说不清楚,走一步看一步吧。CTSC2016, SDOI2016 Round2 Bless All!

转载于:https://www.cnblogs.com/abclzr/p/5380247.html

你可能感兴趣的:(数据结构与算法)