Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <vector>
- #include <queue>
- #include <climits>
- #include <cstring>
- using namespace std;
- const int INF = INT_MAX;
- // Структура для представления ребра
- struct Edge {
- int to, capacity, cost, flow, reverse;
- };
- vector<vector<Edge>> graph;
- int N, M; // Количество чисел и регистров
- // Добавление ребра в граф
- void addEdge(int from, int to, int capacity, int cost) {
- Edge forward = {to, capacity, cost, 0, (int)graph[to].size()};
- Edge backward = {from, 0, -cost, 0, (int)graph[from].size()};
- graph[from].push_back(forward);
- graph[to].push_back(backward);
- }
- // Подсчет количества единичных битов (popcount)
- int popcount(int x) {
- return __builtin_popcount(x);
- }
- // MinCostMaxFlow с использованием Беллмана-Форда
- pair<int, int> minCostMaxFlow(int source, int sink, int nodes) {
- int flow = 0, cost = 0;
- while (true) {
- vector<int> dist(nodes, INF), parent(nodes, -1), parentEdge(nodes, -1);
- vector<bool> inQueue(nodes, 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 i = 0; i < (int)graph[u].size(); ++i) {
- Edge &e = graph[u][i];
- if (e.flow < e.capacity && dist[u] + e.cost < dist[e.to]) {
- dist[e.to] = dist[u] + e.cost;
- parent[e.to] = u;
- parentEdge[e.to] = i;
- if (!inQueue[e.to]) {
- q.push(e.to);
- inQueue[e.to] = true;
- }
- }
- }
- }
- if (dist[sink] == INF) break; // Если путь до стока не найден
- // Найти минимальный остаточный поток по пути
- int pushFlow = INF;
- for (int u = sink; u != source; u = parent[u]) {
- int prev = parent[u];
- int edgeIdx = parentEdge[u];
- pushFlow = min(pushFlow, graph[prev][edgeIdx].capacity - graph[prev][edgeIdx].flow);
- }
- // Пропустить поток и обновить ребра
- for (int u = sink; u != source; u = parent[u]) {
- int prev = parent[u];
- int edgeIdx = parentEdge[u];
- graph[prev][edgeIdx].flow += pushFlow;
- graph[u][graph[prev][edgeIdx].reverse].flow -= pushFlow;
- cost += pushFlow * graph[prev][edgeIdx].cost;
- }
- flow += pushFlow;
- }
- return {flow, cost};
- }
- int main() {
- cin >> N >> M;
- vector<int> sequence(N);
- for (int i = 0; i < N; ++i) {
- cin >> sequence[i];
- }
- int source = 0;
- int sink = N + N + M + 1; // Источник + write[i] + print[i] + регистры + сток
- graph.resize(sink + 1);
- // Добавляем вершины для записи чисел
- for (int i = 0; i < N; ++i) {
- addEdge(source, i + 1, 1, popcount(sequence[i])); // S -> write[i]
- addEdge(i + 1, N + i + 1, 1, 0); // write[i] -> print[i]
- addEdge(N + i + 1, sink, 1, 0); // print[i] -> T
- }
- // Добавляем регистры
- for (int j = 0; j < M; ++j) {
- for (int i = 0; i < N; ++i) {
- addEdge(i + 1, 2 * N + j + 1, 1, 0); // write[i] -> reg[j]
- addEdge(2 * N + j + 1, N + i + 1, 1, 0); // reg[j] -> print[i]
- }
- }
- // Выполняем MinCostMaxFlow
- auto result = minCostMaxFlow(source, sink, sink + 1);
- cout << "Минимальная стоимость: " << result.second << endl;
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement