Submission #1268925

#TimeUsernameProblemLanguageResultExecution timeMemory
1268925TINDomino (COCI15_domino)C++17
150 / 160
402 ms114792 KiB
#include <bits/stdc++.h>

#define FNAME "test"

using namespace std;

template<typename T> using min_heap = priority_queue<T,vector<T>,greater<T>>;

template<class X, class Y>
bool minimize(X& x, const Y& y) {
	if (x > y) {
		x = y;
		return true;
	}
	return false;
}

template<class Cost, class Flow>
class MinCostFlow {
private:
	struct Edge {
		int from, to;
		Flow capa, flow;
		Cost cost;

		Edge(int _from, int _to, Flow _capa, Cost _cost) {
			from = _from; to = _to;
			capa = _capa; flow = Flow(0);
			cost = _cost;
		}

		Flow residual() const {
			return capa - flow;
		}
	};

	int numNode;
	vector<Edge> edges;
	vector<vector<int>> adj;
	vector<Cost> dist;
	vector<int> par;
	vector<bool> inQueue;

	bool fordBellman(int source, int sink) {
		fill(dist.begin(), dist.end(), numeric_limits<Cost>::max());
		fill(par.begin(), par.end(), -1);
		fill(inQueue.begin(), inQueue.end(), false);
		queue<int> q;
		dist[source] = 0; q.push(source); inQueue[source] = true;
		while (!q.empty()) {
			int u = q.front(); q.pop(); inQueue[u] = false;
			for (int edgeID : adj[u]) if (edges[edgeID].residual() > Flow(0)) {
				int v = edges[edgeID].to;
				Cost cost = edges[edgeID].cost;
				if (minimize(dist[v], dist[u] + cost)) {
					par[v] = edgeID;
					if (!inQueue[v]) {
						q.push(v);
						inQueue[v] = true;
					}
				}
			}
		}
		return dist[sink] < numeric_limits<Cost>::max();
	}
public:
	MinCostFlow(int _numNode = 0) {
		numNode = _numNode;
		edges.clear();
		adj.assign(_numNode, vector<int>());
		dist.assign(_numNode, Cost(0));
		par.assign(_numNode, -1);
		inQueue.assign(_numNode, false);
	}

	void addEdge(int from, int to, Flow capa, Cost cost) {
		adj[from].push_back(edges.size());
		edges.push_back(Edge(from, to, capa, cost));
		adj[to].push_back(edges.size());
		edges.push_back(Edge(to, from, Flow(0), -cost));
	}

	pair<Cost,Flow> getMCMF(int source, int sink, Flow desiredFlow = numeric_limits<Flow>::max()) {
		Cost totalCost = Cost(0);
		Flow totalFlow = Flow(0);
		while (fordBellman(source, sink) && totalFlow < desiredFlow) {
			Flow delta = desiredFlow - totalFlow;
			for (int node = sink; node != source; node = edges[par[node]].from)
				minimize(delta, edges[par[node]].residual());
			totalFlow += delta;
			totalCost += dist[sink] * Cost(delta);
			for (int node = sink; node != source; node = edges[par[node]].from) {
				edges[par[node]].flow += delta;
				edges[par[node] ^ 1].flow -= delta;
			}
		}
		if (desiredFlow != numeric_limits<Flow>::max()) {
			if (totalFlow != desiredFlow) {
				totalFlow = -1;
			}
		}
		return make_pair(totalCost, totalFlow);
	}
};

void Task() {
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	if (fopen(FNAME".inp","r")) {
		freopen(FNAME".inp","r",stdin);
		freopen(FNAME".out","w",stdout);
	}
}

void Solve() {
	int tableSize, numDomino;
	cin >> tableSize >> numDomino;
	vector<vector<int>> grid(tableSize, vector<int>(tableSize));
	for (int row = 0; row < tableSize; ++row) {
		for (int col = 0; col < tableSize; ++col) {
			cin >> grid[row][col];
		}
	}
	auto cellID = [&](int row, int col) -> int {
		return row * tableSize + col;
	};
	min_heap<pair<int,pair<int,int>>> pq;
	int ans = 0;
	for (int row = 0; row < tableSize; ++row) {
		for (int col = 0; col < tableSize; ++col) {
			ans += grid[row][col];
			if ((row + col) % 2 == 1) continue;
			if (row - 1 >= 0) {
				int cost = -(grid[row][col] + grid[row - 1][col]);
				pq.push({cost, {cellID(row,col), cellID(row - 1, col)}});
			}
			if (row + 1 < tableSize) {
				int cost = -(grid[row][col] + grid[row + 1][col]);
				pq.push({cost, {cellID(row,col), cellID(row + 1, col)}});
			}
			if (col - 1 >= 0) {
				int cost = -(grid[row][col] + grid[row][col - 1]);
				pq.push({cost, {cellID(row,col), cellID(row, col - 1)}});
			}
			if (col + 1 < tableSize) {
				int cost = -(grid[row][col] + grid[row][col + 1]);
				pq.push({cost, {cellID(row,col), cellID(row, col + 1)}});
			}
		}
	}
	int numNeed = min(8 * numDomino, (int) pq.size());
	vector<pair<int,pair<int,int>>> edges;
	for (int i = 1; i <= numNeed; ++i) {
		edges.push_back(pq.top());
		pq.pop();
	}
	vector<int> vec;
	for (auto e : edges) {
		vec.push_back(e.second.first);
		vec.push_back(e.second.second);
	}
	sort(vec.begin(), vec.end());
	vec.resize(unique(vec.begin(), vec.end()) - vec.begin());
	int numNode = (int) vec.size() + 2;
	vector<int> halfA, halfB;
	for (auto& e : edges) {
		e.second.first = lower_bound(vec.begin(), vec.end(), e.second.first) - vec.begin() + 1;
		halfA.push_back(e.second.first);
		e.second.second = lower_bound(vec.begin(), vec.end(), e.second.second) - vec.begin() + 1;
		halfB.push_back(e.second.second);
	}
	for (int _ = 0; _ < 2; _++) {
		sort(halfA.begin(), halfA.end());
		halfA.resize(unique(halfA.begin(), halfA.end()) - halfA.begin());
		swap(halfA, halfB);
	}
	MinCostFlow<int,int> solver(numNode);
	int source = 0, sink = numNode - 1;
	for (int node : halfA) solver.addEdge(source, node, 1, 0);
	for (auto e : edges) solver.addEdge(e.second.first, e.second.second, 1, e.first);
	for (int node : halfB) solver.addEdge(node, sink, 1, 0);
	int totalCost, totalFlow;
	tie(totalCost, totalFlow) = solver.getMCMF(source, sink, numDomino);
	ans += totalCost;
	cout << ans;
}

int main() {
	Task();
	Solve();
	return 0;
}

Compilation message (stderr)

domino.cpp: In function 'void Task()':
domino.cpp:110:24: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  110 |                 freopen(FNAME".inp","r",stdin);
      |                 ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
domino.cpp:111:24: warning: ignoring return value of 'FILE* freopen(const char*, const char*, FILE*)' declared with attribute 'warn_unused_result' [-Wunused-result]
  111 |                 freopen(FNAME".out","w",stdout);
      |                 ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...