列表

详情


NC17063. 集合

描述

A 集合有 N 个元素,分别为 A1, A2, A3, ... ..., AN
B 集合有 M 个元素,分别为 B1, B2, B3, ... ..., BM
两个集合中的元素均为 01 字符串(字符串中只包含两种字符,0 和 1 )。
每次操作,你可以在以下两种方式中选择一种:

删除:将某个集合中的某个元素删除。(每个元素只能被删除一次,删除一次之后就没了)
修改:将某个集合中的某个元素的一段区间倒置。(例如元素 10010,将区间 [1,3] 倒置后得到 00110 )

删除 A 集合中第 i 个元素的花费为 dai
删除 B 集合中第 i 个元素的花费为 dbi
修改一次 A 集合中第 i 个元素的花费为 mai
修改一次 B 集合中第 i 个元素的花费为 mbi

请问,让 A 集合和 B 集合相等的最小花费是多少?

输入描述

第一行输入一个整数 N,表示 A 集合有 N 个元素。
第二行输入 N 个互不相同的 01 字符串,表示 A1, A2, A3, ... ..., AN
第三行输入一个整数 M,表示 B 集合有 M 个元素。
第四行输入 M 个互不相同的 01 字符串,表示 B1, B2, B3, ... ..., BM
第五行输入 N 个整数,表示 da1, da2, da3, ... ..., daN
第六行输入 M 个整数,表示 db1, db2, db3, ... ..., dbM
第七行输入 N 个整数,表示 ma1, ma2, ma3, ... ..., maN
第八行输入 M 个整数,表示 mb1, mb2, mb3, ... ..., mbM
0 ≤ N,M ≤ 50.
1 ≤ |Ai|,|Bi| ≤ 16.
1 ≤ dai, dbi, mai, mbi ≤ 1000.

输出描述

输出一个整数,表示最小花费。

示例1

输入:

5
000111 101010 000001 100 0
6
110110 011010 001101 010 1 001
1 1 1 1 1
1 1 1 1 1 1
4 5 1 6 2
6 3 2 1 4 5

输出:

10

示例2

输入:

5
000111 101010 000001 100 0
6
110110 011010 001101 010 1 001
4 5 1 6 2
6 3 2 1 4 5
1 1 1 1 1
1 1 1 1 1 1

输出:

17

说明:

集合具有无序性,例如 { 10100,11,101} = { 101,10100,11}。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 1208ms, 内存消耗: 7396K, 提交时间: 2018-07-06 20:43:59

#include <bits/stdc++.h>
using namespace std;
const int maxn = 105, maxm = 3001, maxl = 17, maxd = 1 << 16 | 1, INF = 0x3f3f3f3f;
int N, M, S, T, flow, cost, lnk[maxn], d[maxn], p[maxn], a[maxn];
bool inq[maxn];
struct Edge {
	int nxt, v, w, c;
} e[maxm << 1 | 1];
void addEdge(int u, int v, int w, int c) {
	e[M] = (Edge){lnk[u], v, w, c};
	lnk[u] = M++;
	e[M] = (Edge){lnk[v], u, 0, -c};
	lnk[v] = M++;
}
bool BellmanFord() {
	memset(d, 0x3f, N * sizeof(int));
	memset(inq, 0, N * sizeof(bool));
	d[S] = 0;
	inq[S] = 1;
	p[S] = 0;
	a[S] = INF;
	queue<int> Q;
	Q.push(S);
	while(!Q.empty()) {
		int u = Q.front();
		Q.pop();
		inq[u] = 0;
		for(int it = lnk[u]; it != -1;it = e[it].nxt) {
			int v = e[it].v;
			if(e[it].w > 0 && d[v] > d[u] + e[it].c) {
				d[v] = d[u] + e[it].c;
				p[v] = it;
				a[v] = min(a[u], e[it].w);
				if(!inq[v]) {
					Q.push(v);
					inq[v] = 1;
				}
			}
		}
	}
	if(d[T] == INF)
		return 0;
	flow += a[T];
	cost += d[T] * a[T];
	for(int u = T; u != S; u = e[p[u] ^ 1].v) {
		e[p[u]].w -= a[T];
		e[p[u] ^ 1].w += a[T];
	}
	return 1;
}
int bits[maxd], rev[maxl][maxd], cnt[maxl], idx[maxd];
int n, m, len[maxn], msk[maxn], dc[maxn], mc[maxn], dis[maxn][maxd];
void scanBinary(int &len, int &msk) {
	static char buf[maxl];
	scanf("%s", buf);
	len = strlen(buf);
	msk = 0;
	for(int i = 0; i < len; ++i)
		msk = msk << 1 | (buf[i] - '0');
}
int main() {
	for(int i = 1; i < maxd; ++i)
		bits[i] = bits[i >> 1] + (i & 1);
	for(int i = 0; i < maxd; ++i)
		idx[i] = cnt[bits[i]]++;
	for(int i = 1; i < maxl; ++i)
		for(int j = 1; j < 1 << i; ++j)
			rev[i][j] = rev[i - 1][j >> 1] | ((j & 1) << (i - 1));
	scanf("%d", &n);
	for(int i = 0; i < n; ++i)
		scanBinary(len[i], msk[i]);
	scanf("%d", &m);
	for(int i = n; i < n + m; ++i)
		scanBinary(len[i], msk[i]);
	for(int i = 0; i < n + m; ++i)
		scanf("%d", dc + i);
	for(int i = 0; i < n + m; ++i)
		scanf("%d", mc + i);
	for(int i = 0; i < n + m; ++i) {
		int LEN = len[i], *DIS = dis[i], qL = 0, qR = 0;
		static int que[maxd];
		memset(DIS, -1, cnt[bits[msk[i]]] * sizeof(int));
		que[qR++] = msk[i];
		DIS[idx[msk[i]]] = 0;
		while(qL < qR) {
			int u = que[qL++];
			for(int len = 2; len <= LEN; ++len) {
				int all = (1 << len) - 1;
				for(int L = 0, R = L + len - 1; R < LEN; ++L, ++R) {
					int msk = (u >> L) & all;
					int v = u ^ ((msk ^ rev[len][msk]) << L);
					if(DIS[idx[v]] == -1) {
						DIS[idx[v]] = DIS[idx[u]] + 1;
						que[qR++] = v;
					}
				}
			}
		}
	}
	N = n + m + 4;
	M = 0;
	int PS = N - 4;
	int PT = N - 3;
	S = N - 2;
	T = N - 1;
	memset(lnk, -1, N * sizeof(int));
	for(int i = 0; i < n; ++i) {
		addEdge(S, i, 1, 0);
		addEdge(PS, T, 1, 0);
		addEdge(i, PT, 1, dc[i]);
	}
	for(int i = n; i < n + m; ++i) {
		addEdge(S, PT, 1, 0);
		addEdge(i, T, 1, 0);
		addEdge(PS, i, 1, dc[i]);
	}
	for(int i = 0; i < n; ++i)
		for(int j = n; j < n + m; ++j) {
			if(len[i] != len[j] || bits[msk[i]] != bits[msk[j]])
				continue;
			int low = INF;
			for(int k = 0; k < cnt[bits[msk[i]]]; ++k)
				if(dis[i][k] != -1 && dis[j][k] != -1)
					low = min(low, mc[i] * dis[i][k] + mc[j] * dis[j][k]);
			addEdge(i, j, 1, low);
		}
	addEdge(PT, PS, INF, 0);
	while(BellmanFord());
	printf("%d\n", cost);
	return 0;
}

上一题