Baltic OI 2015 - Tug of War

Author: Andi Qu

Official Analysis

Making Cycles

Imagine we have a bipartite graph where each spot is a node and each person is an edge between the two spots they're willing to take.

If any node has degree equal to 0, then it's not possible to assign the teams.

If any node has degree equal to 1, then we must assign the person willing to take that spot to it. After assigning that person, we can delete the node and edge from the graph.

We can repeatedly assign people to and delete nodes with degree equal to 1 by using a BFS. After doing this, all nodes will have degree greater than 1.

However, if any node has degree greater than 2, then by the pigeonhole principle, there must be a node with degree equal to less than 2, which isn't possible.

Thus, we are left with several disjoint simple cycles. Since this is a bipartite graph, these cycle lengths are all even.

Using Knapsack DP

Let the set of all cycles be CC and let the difference in strengths from the nodes we previously deleted be dd.

Consider a single cycle. Notice how if a person/edge is assigned to some side, then the next person must be assigned to the opposite side.

This means that each cycle contributes a fixed amount to the difference in strengths! Let the absolute value of this amount for the ii-th cycle be ViV_i.

We now only need to check whether there exist 2 disjoint sets SS and TT such that ST=CS \cup T = C and

d+iTViiSViK\left |d + \sum_{i \in T} V_i - \sum_{i \in S} V_i \right | \leq K

This is the same as checking whether a subset SS of CC exists such that

d+iCVi2iSViK\left |d + \sum_{i \in C} V_i - 2 \sum_{i \in S} V_i \right | \leq K

We can check this using knapsack DP in O(NK)\mathcal{O}(NK) time.

Since we are only checking whether we can obtain some value, we can use a bitset to speed this up.

The final complexity is O(NK/64)\mathcal{O}(NK / 64), which is fast enough for 100 points.

Implementation

#include <bits/stdc++.h>
using namespace std;
multiset<pair<int, int>> graph[60001];
bool visited[60001];
bitset<600001> possible;
int tot = 0, sm = 0;
void dfs(int node) {
visited[node] = true;

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!