https://ac.nowcoder.com/acm/contest/5673/I
题意
给了两个数组:({a_1, a_2, dots a_n}, {b_1, b_2, dots b_n})
第i步可以从(a_i)和(b_i)中选择一个数。
求最后选出的数中,不同的数要最多
题解
正解是把每个点对((a_i,b_i))当成一个图中的一条边,如果一个联通分量中有环,则所有点都可以取到,若为树形结构,那么只能取到k-1个点,用并查集判断有没有环即可
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
struct READ {
inline char read() {
#ifdef Artoriax
return getchar();
#endif
const int LEN = 1 << 18 | 1;
static char buf[LEN], *s, *t;
return (s == t) && (t = (s = buf) + fread(buf, 1, LEN, stdin)), s == t ? -1 : *s++;
}
inline READ & operator >> (char *s) {
char ch;
while (isspace(ch = read()) && ~ch);
while (!isspace(ch) && ~ch) *s++ = ch, ch = read(); *s = ' ';
return *this;
}
inline READ & operator >> (string &s) {
s = ""; char ch;
while (isspace(ch = read()) && ~ch);
while (!isspace(ch) && ~ch) s += ch, ch = read();
return *this;
}
template <typename _Tp> inline READ & operator >> (_Tp&x) {
char ch, flag;
for(ch = read(),flag = 0; !isdigit(ch) && ~ch; ch = read()) flag |= ch == '-';
for(x = 0; isdigit(ch); ch = read()) x = x * 10 + (ch ^ '0');
flag && (x = -x);
return *this;
}
} in;
const int N = 2e5 + 50;
int f[N];
int a[N], b[N], lis[N], vis[N];
int find(int x) {
return f[x] == x ? x : f[x] = find(f[x]);
}
int main() {
int _; in >> _;
for (int t = 1; t <= _; t++) {
int n; in >> n;
for (int i = 1; i <= n; i++) {
in >> a[i] >> b[i];
lis[i*2-1] = a[i], lis[i*2] = b[i];
}
sort(lis + 1, lis + 2 * n + 1);
int m = unique(lis + 1, lis + 2 * n + 1) - lis - 1;
for (int i = 1; i <= m; i++) f[i] = i, vis[i] = 0;
for (int i = 1; i <= n; i++) {
a[i] = lower_bound(lis + 1, lis + m + 1, a[i]) - lis;
b[i] = lower_bound(lis + 1, lis + m + 1, b[i]) - lis;
int x = find(a[i]), y = find(b[i]);
if (x == y) vis[x] = vis[y] = 1;
else {
f[y] = x;
if (vis[y]) vis[x] = 1;
}
}
int ans = m;
for (int i = 1; i <= m; i++) {
f[i] = find(f[i]);
if (f[i] == i && !vis[i]) ans--;
}
printf("Case #%d: %d
", t, ans);
}
return 0;
}
比赛的时候是直接用二分图匹配求解的,用isap卡过去了,二分图的建立方式即i向a[i],b[i]分别连边
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct READ {
inline char read() {
#ifdef _WIN32
return getchar();
#endif
static const int IN_LEN = 1 << 18 | 1;
static char buf[IN_LEN], *s, *t;
return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
}
template <typename _Tp> inline READ & operator >> (_Tp&x) {
static char c11, boo;
for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
if(c11 == -1) return *this;
boo |= c11 == '-';
}
for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
boo && (x = -x);
return *this;
}
} in;
const int inf = 0x3f3f3f3f;
const int N = 3e5 + 50;
struct node {
int v, cap, flow, nxt;
node () {}
node (int v, int cap, int flow, int nxt): v(v), cap(cap), flow(flow), nxt(nxt) {}
} edge[N * 10];
int head[N], tot;
void init() {
memset(head, -1, sizeof(head));
tot = 0;
}
int dep[N];
void adde(int u, int v, int w) {
edge[tot] = node(v, w, 0, head[u]);
head[u] = tot++;
edge[tot] = node(u, 0, 0, head[v]);
head[v] = tot++;
}
int gap[N], cur[N];
void bfs(int s, int t) {
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
gap[0] = 1;
queue<int> q;
dep[t] = 0;
q.push(t);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (dep[v] != -1) continue;
q.push(v);
dep[v] = dep[u] + 1;
gap[dep[v]]++;
}
}
}
int S[N];
int sap(int s, int t, int n) {
bfs(s, t);
memcpy(cur, head, sizeof(head));
int top = 0;
int u = s;
int ans = 0;
while (dep[s] < n) {
if (u == t) {
int minn = inf;
int inser;
for (int i = 0; i < top; i++) {
if (minn > edge[S[i]].cap - edge[S[i]].flow) {
minn = edge[S[i]].cap - edge[S[i]].flow;
inser = i;
}
}
for (int i = 0; i < top; i++) {
edge[S[i]].flow += minn;
edge[S[i] ^ 1].flow -= minn;
}
ans += minn;
top = inser;
u = edge[S[top] ^ 1].v;
continue;
}
bool flag = false;
int v;
for (int i = cur[u]; ~i; i = edge[i].nxt) {
v = edge[i].v;
if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u]) {
flag = true;
cur[u] = i;
break;
}
}
if (flag) {
S[top++] = cur[u];
u = v;
continue;
}
int minn = n;
for (int i = head[u]; ~i; i = edge[i].nxt) {
if (edge[i].cap - edge[i].flow && dep[edge[i].v] < minn) {
minn = dep[edge[i].v];
cur[u] = i;
}
}
gap[dep[u]]--;
if (!gap[dep[u]]) return ans;
dep[u] = minn + 1;
gap[dep[u]]++;
if (u != s) u = edge[S[--top] ^ 1].v;
}
return ans;
}
int main() {
int t; in >> t;
int cse = 0;
while (t--) {
init();
int n; in >> n;
map<int, int> mp;
int cnt = 0;
for (int i = 1; i <= n; i++) {
int u, v;
in >> u >> v;
if (!mp.count(u)) mp[u] = ++cnt;
if (!mp.count(v)) mp[v] = ++cnt;
u = mp[u];
v = mp[v];
adde(i, u + n, 1);
adde(i, v + n, 1);
}
for (int i = 1; i <= n; i++) {
adde(0, i, 1);
}
for (int i = 1; i <= cnt; i++) {
adde(i + n, n + cnt + 1, 1);
}
printf("Case #%d: %d
", ++cse, sap(0, n + cnt + 1, n + cnt + 1));
}
return 0;
}