250705 Rounding

Jongleee·2025년 7월 5일
0

TIL

목록 보기
950/970
static class Edge {
	int to, capacity, lowerBound, initialFlow, flow;
	Edge dual;

	Edge(int to, int capacity, int lowerBound) {
		this.to = to;
		this.capacity = capacity;
		this.lowerBound = lowerBound;
		this.initialFlow = 0;
		this.flow = 0;
	}

	int spare() {
		return capacity - flow;
	}

	void addFlow(int flowAmount) {
		this.flow += flowAmount;
		this.dual.flow -= flowAmount;
	}
}

static class Dinic {
	static final int MAX_N = 200;
	static final int MAX_V = 2 * MAX_N * (MAX_N + 1) + 4;
	static final int INF = 1_000_000_000;

	int rowCount, colCount, totalDemand;
	int source = MAX_V - 2;
	int sink = MAX_V - 1;
	int s0 = MAX_V - 4;
	int e0 = MAX_V - 3;

	int[] level = new int[MAX_V];
	int[] work = new int[MAX_V];

	Edge[] rowSumEdges = new Edge[MAX_N];
	Edge[] colSumEdges = new Edge[MAX_N];
	Edge[][] cellEdges = new Edge[MAX_N][MAX_N];

	List<Edge> allEdges = new ArrayList<>();
	@SuppressWarnings("unchecked")
	List<Edge>[] adj = new ArrayList[MAX_V];

	Dinic() {
		for (int i = 0; i < MAX_V; i++)
			adj[i] = new ArrayList<>();
	}

	void run(BufferedReader br, BufferedWriter bw) throws IOException {
		initializeGraph(br);
		solveMaxFlow();
		printResult(bw);
	}

	void initializeGraph(BufferedReader br) throws IOException {
		int[][] cell = new int[MAX_N][MAX_N];
		int[][] cellM = new int[MAX_N][MAX_N];
		int[] rowSum = new int[MAX_N];
		int[] rowSumM = new int[MAX_N];
		int[] colSum = new int[MAX_N];
		int[] colSumM = new int[MAX_N];

		StringTokenizer st = new StringTokenizer(br.readLine());
		rowCount = Integer.parseInt(st.nextToken());
		colCount = Integer.parseInt(st.nextToken());

		for (int i = 0; i < rowCount; i++) {
			st = new StringTokenizer(br.readLine());
			for (int j = 0; j < colCount; j++) {
				String[] parts = st.nextToken().split("\\.");
				cell[i][j] = Integer.parseInt(parts[0]);
				cellM[i][j] = Integer.parseInt(parts[1]);
			}
			String[] sumParts = st.nextToken().split("\\.");
			rowSum[i] = Integer.parseInt(sumParts[0]);
			rowSumM[i] = Integer.parseInt(sumParts[1]);
		}

		st = new StringTokenizer(br.readLine());
		for (int j = 0; j < colCount; j++) {
			String[] sumParts = st.nextToken().split("\\.");
			colSum[j] = Integer.parseInt(sumParts[0]);
			colSumM[j] = Integer.parseInt(sumParts[1]);
		}

		for (int i = 0; i < rowCount; i++) {
			rowSumEdges[i] = addEdge(s0, 2 * MAX_N * MAX_N + i, rowSum[i] + (rowSumM[i] > 0 ? 1 : 0), rowSum[i]);
			for (int j = 0; j < colCount; j++) {
				addEdge(2 * MAX_N * MAX_N + i, (MAX_N * i + j) * 2, INF, 0);
			}
		}

		for (int j = 0; j < colCount; j++) {
			colSumEdges[j] = addEdge(2 * MAX_N * MAX_N + MAX_N + j, e0, colSum[j] + (colSumM[j] > 0 ? 1 : 0),
					colSum[j]);
			for (int i = 0; i < rowCount; i++) {
				addEdge((MAX_N * i + j) * 2 + 1, 2 * MAX_N * MAX_N + MAX_N + j, INF, 0);
			}
		}

		for (int i = 0; i < rowCount; i++) {
			for (int j = 0; j < colCount; j++) {
				cellEdges[i][j] = addEdge((MAX_N * i + j) * 2, (MAX_N * i + j) * 2 + 1,
						cell[i][j] + (cellM[i][j] > 0 ? 1 : 0), cell[i][j]);
			}
		}

		addEdge(e0, s0, INF, 0);

		int[] demand = new int[MAX_V - 2];
		for (Edge e : allEdges) {
			if (e.lowerBound > 0) {
				demand[e.to] -= e.lowerBound;
				demand[e.dual.to] += e.lowerBound;
				e.capacity -= e.lowerBound;
				e.initialFlow = e.lowerBound;
				e.lowerBound = 0;
			}
		}

		totalDemand = 0;
		for (int i = 0; i < MAX_V - 2; i++) {
			if (demand[i] < 0)
				addEdge(source, i, -demand[i], 0);
			else if (demand[i] > 0) {
				addEdge(i, sink, demand[i], 0);
				totalDemand += demand[i];
			}
		}
	}

	void solveMaxFlow() {
		while (bfs()) {
			Arrays.fill(work, 0);
			int flow;
			while ((flow = dfs(source, sink, INF)) > 0) {
				totalDemand -= flow;
			}
		}
	}

	void printResult(BufferedWriter bw) throws IOException {
		for (int i = 0; i < rowCount; i++) {
			for (int j = 0; j < colCount; j++) {
				bw.write((cellEdges[i][j].flow + cellEdges[i][j].initialFlow) + " ");
			}
			bw.write((rowSumEdges[i].flow + rowSumEdges[i].initialFlow) + "\n");
		}
		for (int j = 0; j < colCount; j++) {
			bw.write((colSumEdges[j].flow + colSumEdges[j].initialFlow) + " ");
		}
		bw.flush();
	}

	Edge addEdge(int u, int v, int capacity, int lowerBound) {
		Edge e1 = new Edge(v, capacity, lowerBound);
		Edge e2 = new Edge(u, 0, 0);
		e1.dual = e2;
		e2.dual = e1;
		adj[u].add(e1);
		adj[v].add(e2);
		allEdges.add(e1);
		allEdges.add(e2);
		return e1;
	}

	boolean bfs() {
		Arrays.fill(level, -1);
		Queue<Integer> queue = new LinkedList<>();
		queue.offer(source);
		level[source] = 0;
		while (!queue.isEmpty()) {
			int current = queue.poll();
			for (Edge e : adj[current]) {
				int next = e.to;
				if (level[next] == -1 && e.spare() > 0) {
					level[next] = level[current] + 1;
					queue.offer(next);
				}
			}
		}
		return level[sink] != -1;
	}

	int dfs(int current, int dest, int flow) {
		if (current == dest)
			return flow;
		for (; work[current] < adj[current].size(); work[current]++) {
			Edge e = adj[current].get(work[current]);
			int next = e.to;
			if (level[next] == level[current] + 1 && e.spare() > 0) {
				int pushed = dfs(next, dest, Math.min(flow, e.spare()));
				if (pushed > 0) {
					e.addFlow(pushed);
					return pushed;
				}
			}
		}
		return 0;
	}
}

public static void main(String[] args) throws IOException {
	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	new Dinic().run(br, bw);
}

출처:https://www.acmicpc.net/problem/13569

0개의 댓글