├── Algorithm.txt ├── Code(C++).cpp ├── Code(Python).py ├── Code(java).java ├── Problem explanation.txt └── Time Complexity.txt /Algorithm.txt: -------------------------------------------------------------------------------- 1 | The provided code appears to be implementing a solution for joining cells in a matrix into cycles while minimizing the cost. Each cell in the matrix represents a node, and the cells are connected by neighboring cells in four directions: up, down, left, and right. The goal is to join cells together to form cycles by assigning a direction to each cell. The direction determines which neighboring cell the current cell connects to. 2 | 3 | The algorithm includes several helper methods and a main method called `trySmartJoinCellToCycles`, which attempts to join cells to an existing cycle while minimizing the cost. The algorithm follows a greedy approach, trying to find the best path to join cells together. 4 | 5 | Here's a breakdown of the provided code: 6 | 7 | 1. The code defines a `Direction` enum to represent the four possible directions: Up, Down, Left, and Right. 8 | 9 | 2. The `Cell` class represents a cell in the matrix. It stores the row and column indices of the cell, the direction assigned to the cell, and the indices of the cell where the cycle ends. 10 | 11 | 3. The `findCycledToItselfCells` method iterates over the matrix and finds cells that form cycles with themselves (endCycleRow == row and endCycleCol == col). It returns a list of these cells. 12 | 13 | 4. The `leftNeighbour`, `rightNeighbour`, `upNeighbour`, and `downNeighbour` methods return the neighboring cells of a given cell in the specified direction. 14 | 15 | 5. The `joinSelfCycled` method attempts to join cells that cycle to themselves. It iterates over the cells and tries to find neighboring cells to join. It uses a set called `cellSet` to keep track of cells that have not been joined yet. The method follows specific rules to determine the best direction to join cells together. 16 | 17 | 6. The `countCost` method calculates the total cost of joining cells in the matrix. It iterates over the matrix and sums up the costs based on the assigned directions of the cells. 18 | 19 | 7. The `sameCycle` method checks if two cells belong to the same cycle. It compares the endCycleRow and endCycleCol of the cells. 20 | 21 | 8. The `Path` class represents a path of joined cells. It stores the visited cells, the directions of the joined cells, the last cell in the path, and the total cost of the path. 22 | 23 | 9. The `chooseAnyNonVisited` method returns any non-visited cell from a set of cells. 24 | 25 | 10. The `gcd` method calculates the greatest common divisor of two numbers using the Euclidean algorithm. 26 | 27 | 11. The `lcm` method calculates the least common multiple of two numbers using the formula: lcm(a, b) = a * (b / gcd(a, b)). 28 | 29 | 12. The `compareResults` method compares the total costs and counts of two paths to determine their relative ordering. 30 | 31 | 13. The `trySmartJoinCellToCycles` method attempts to join cells to an existing cycle while minimizing the cost. It uses a priority queue of paths to explore different possibilities. The method iteratively expands the paths until all cells are joined. It chooses the best path based on the total cost and count of joined cells. 32 | 33 | 14. The code snippet provided is incomplete, and there are additional parts missing, such as the remaining implementation of the `trySmartJoinCellToCycles` method. 34 | 35 | Overall, the code aims to solve a combinatorial optimization problem of joining cells in a matrix into cycles with minimal cost. However, without the complete implementation and additional context, it is difficult to provide a more detailed explanation of the algorithm's logic and functionality. 36 | Here's a breakdown of the provided code: 37 | 38 | 1. The code defines a `Direction` enum to represent the four possible directions: Up, Down, Left, and Right. 39 | 40 | 2. The `Cell` class represents a cell in the matrix. It stores the row and column indices of the cell, the direction assigned to the cell, and the indices of the cell where the cycle ends. 41 | 42 | 3. The `findCycledToItselfCells` method iterates over the matrix and finds cells that form cycles with themselves (endCycleRow == row and endCycleCol == col). It returns a list of these cells. 43 | 44 | 4. The `leftNeighbour`, `rightNeighbour`, `upNeighbour`, and `downNeighbour` methods return the neighboring cells of a given cell in the specified direction. 45 | 46 | 5. The `joinSelfCycled` method attempts to join cells that cycle to themselves. It iterates over the cells and tries to find neighboring cells to join. It uses a set called `cellSet` to keep track of cells that have not been joined yet. The method follows specific rules to determine the best direction to join cells together. 47 | 48 | 6. The `countCost` method calculates the total cost of joining cells in the matrix. It iterates over the matrix and sums up the costs based on the assigned directions of the cells. 49 | 50 | 7. The `sameCycle` method checks if two cells belong to the same cycle. It compares the endCycleRow and endCycleCol of the cells. 51 | 52 | 8. The `Path` class represents a path of joined cells. It stores the visited cells, the directions of the joined cells, the last cell in the path, and the total cost of the path. 53 | 54 | 9. The `chooseAnyNonVisited` method returns any non-visited cell from a set of cells. 55 | 56 | 10. The `gcd` method calculates the greatest common divisor of two numbers using the Euclidean algorithm. 57 | 58 | 11. The `lcm` method calculates the least common multiple of two numbers using the formula: lcm(a, b) = a * (b / gcd(a, b)). 59 | 60 | 12. The `compareResults` method compares the total costs and counts of two paths to determine their relative ordering. 61 | 62 | 13. The `trySmartJoinCellToCycles` method attempts to join cells to an existing cycle while minimizing the cost. It uses a priority queue of paths to explore different possibilities. The method iteratively expands the paths until all cells are joined. It chooses the best path based on the total cost and count of joined cells. 63 | 64 | 14. The code snippet provided is incomplete, and there are additional parts missing, such as the remaining implementation of the `trySmartJoinCellToCycles` method. 65 | -------------------------------------------------------------------------------- /Code(C++).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | #define F first 4 | #define S second 5 | #define ignore ignore 6 | #define pb emplace_back 7 | #define mt make_tuple 8 | #define gcd __gcd 9 | // Input 10 | #define in(a) scanf("%d",&a) 11 | #define in2(a,b) scanf("%d%d",&a,&b) 12 | #define in3(a,b,c) scanf("%d%d%d",&a,&b,&c) 13 | #define in4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d) 14 | #define inp(p) in2(p.F,p.S) 15 | #define llin(a) cin >> a 16 | #define llin2(a,b) cin >> a >> b 17 | #define llin3(a,b,c) cin >> a >> b >> c 18 | #define inl(a) scanf("%lld",&a) 19 | #define read(v,i,n) for(i=0;i=0;--i) 45 | #define lp(i,a,b) for(i=a;i=b;--i) 47 | #define all(vec) vec.begin(),vec.end() 48 | #define lower(v,k) lower_bound(v.begin(),v.end(),k)-v.begin() 49 | #define upper(v,k) upper_bound(v.begin(),v.end(),k)-v.begin() 50 | #define tf(mytuple) get<0>(mytuple) 51 | #define ts(mytuple) get<1>(mytuple) 52 | #define tt(mytuple) get<2>(mytuple) 53 | // function 54 | #define sz(x) (int)x.size() 55 | #define inrange(i,a,b) (i>=a && i<=b) 56 | #define FLUSH fflush(stdout) 57 | #define precision(x) cout << setprecision(x) << fixed 58 | #define remax(a,b) a=max(a,b) 59 | #define remin(a,b) a=min(a,b) 60 | #define middle() ((l+h)/2) 61 | #define lchild(p) 2*p 62 | #define rchild(p) 2*p+1 63 | #define lseg l,m,2*p 64 | #define rseg m+1,h,2*p+1 65 | #define bhardo(mat,i,j,n,m,t) rep(i,n){rep(j,m)mat[i][j]=t;} 66 | #define baselog2(n) __lg(n) 67 | #define numberofbit(n) (32-__builtin_clz(n)) 68 | #define numberofbitll(n) (64-__builtin_clzll(n)) 69 | #define onbitcount(x) __builtin_popcount(x) 70 | #define onbitcountll(x) __builtin_popcountll(x) 71 | #define biton(mask,i) ((mask>>i)&1) 72 | #define bitoff(mask,i) (!((mask>>i)&1)) 73 | #define toggle(mask,i) (mask^=(1<<(i))) 74 | #define raise(i) (1<<(i)) 75 | #define mul(p,q) ((ll)(p)*(ll)(q)) 76 | // Debug 77 | #define dbg(v,i,n) for(i=0;i _it(_ss); err(_it, args); } 80 | void err(istream_iterator it) {} 81 | template 82 | void err(istream_iterator it, T a, Args... args) 83 | { 84 | cerr << *it << " = " << a << "\n"; 85 | err(++it, args...); 86 | } 87 | // Data Type 88 | #define ll long long int 89 | #define ii pair 90 | #define pli pair 91 | #define lii pair 92 | #define triple tuple 93 | #define vi vector 94 | #define vll vector 95 | #define vii vector > 96 | #define vvi vector > 97 | #define viii vector,int> > 98 | #define vvii vector > > 99 | // Constant 100 | const double PI = acos(-1); 101 | const double eps = (1e-9); 102 | const ll INF = 2e18; 103 | const int M = (1e9)+7; 104 | //const int M= 998244353; 105 | const int N = 53; // check the limit, man 106 | /** 107 | Have you worked on Simplification of Idea? 108 | Ok! let's code, check whether it is correct or not? 109 | */ 110 | struct bipartite_matching // Hopcroft-Karp Algorithm works in O(E*sqrt(V)) 111 | { 112 | int n,m,root=0; 113 | // n nodes on left side numbered [1,n] and m nodes on right side numbered [n+1,n+m] 114 | vector > graph; 115 | vector lev,match; 116 | bipartite_matching(int l,int r) : n(l),m(r),graph(l+1),lev(l+1),match(l+r+1) {} 117 | void add_edge(int a,int b) // 1-indexing, a->[1,n] and b->[1,m] 118 | { 119 | graph[a].pb(n+b); 120 | } 121 | bool bfs() 122 | { 123 | queue pq; 124 | fill(all(lev),M); 125 | for(int i=1;i<=n;i++)if(match[i]==root)lev[i]=0,pq.push(i); 126 | while(!pq.empty()) 127 | { 128 | int s=pq.front(); pq.pop(); 129 | for(auto a : graph[s]) 130 | if(lev[match[a]]==M)lev[match[a]]=lev[s]+1,pq.push(match[a]); 131 | } 132 | return (lev[root]!=M); 133 | } 134 | bool dfs(int s) 135 | { 136 | if(s==root)return true; 137 | for(auto a : graph[s]) 138 | if(lev[match[a]]==lev[s]+1 && dfs(match[a])) 139 | return match[s]=a,match[a]=s,true; 140 | return lev[s]=M,false; 141 | } 142 | int max_matching() // match array based on [1,n+m] so keep in mind 143 | { 144 | fill(all(match),root); 145 | int ans=0; 146 | while(bfs()) 147 | for(int i=1;i<=n;i++) 148 | if(match[i]==root && dfs(i))ans++; 149 | return ans; 150 | } 151 | }; 152 | ii v[N][N]; 153 | char ans[N][N]; 154 | int I[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; 155 | char ar[4]={'U','D','L','R'}; 156 | void call() 157 | { 158 | out(-1); 159 | exit(0); 160 | } 161 | void solve() 162 | { 163 | int n,i,j,a,b,x,y,c,k; 164 | set st; 165 | in(n); 166 | in4(c,a,b,x); 167 | fone(i,n) 168 | { 169 | fone(j,n) 170 | inp(v[i][j]),st.insert(v[i][j]); 171 | } 172 | bipartite_matching space(n*n,n*n); 173 | for(auto itr=st.begin();itr!=st.end();++itr) 174 | { 175 | tie(x,y)=(*itr); 176 | rep(k,4) 177 | { 178 | a=x+I[k][0],b=y+I[k][1]; 179 | if(st.find({a,b})==st.end()) 180 | continue; 181 | if((x+y)&1) 182 | space.add_edge(n*a+b-n,n*x+y-n); 183 | else 184 | space.add_edge(n*x+y-n,n*a+b-n); 185 | } 186 | } 187 | space.max_matching(); 188 | fone(i,n) 189 | { 190 | fone(j,n) 191 | { 192 | if(space.match[n*i+j-n]==0) 193 | continue; 194 | k=space.match[n*i+j-n]-n*n; 195 | x=((k-1)/n)+1,y=((k-1)%n)+1; 196 | rep(k,4) 197 | { 198 | a=x+I[k][0],b=y+I[k][1]; 199 | if(a==i && b==j) 200 | ans[i][j]=ar[k],ans[x][y]=ar[k^1]; 201 | } 202 | } 203 | } 204 | for(auto itr=st.begin();itr!=st.end();++itr) 205 | { 206 | tie(x,y)=(*itr); 207 | if(ans[x][y]==0) 208 | call(); 209 | queue pq; 210 | pq.push({x,y}); 211 | while(!pq.empty()) 212 | { 213 | tie(a,b)=pq.front(),pq.pop(); 214 | rep(k,4) 215 | { 216 | i=a+I[k][0],j=b+I[k][1]; 217 | if(v[i][j]==make_pair(x,y) && ans[i][j]==0) 218 | ans[i][j]=ar[k],pq.push({i,j}); 219 | } 220 | } 221 | } 222 | fone(i,n) 223 | { 224 | fone(j,n) 225 | if(ans[i][j]==0)call(); 226 | } 227 | llout(n*n*c); 228 | fone(i,n) 229 | { 230 | fone(j,n) 231 | cout << ans[i][j]; 232 | lin; 233 | } 234 | } 235 | void starting() 236 | { 237 | 238 | } 239 | int main() 240 | { 241 | int t=1; 242 | // in(t); 243 | starting(); 244 | while(t--) 245 | solve(); 246 | } 247 | 248 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /Code(Python).py: -------------------------------------------------------------------------------- 1 | 2 | import os, sys, bisect 3 | from collections import defaultdict, Counter, deque; 4 | from functools import lru_cache #use @lru_cache(None) 5 | if os.path.exists('in.txt'): sys.stdin=open('in.txt','r') 6 | if os.path.exists('out.txt'): sys.stdout=open('out.txt', 'w') 7 | # 8 | input = lambda: sys.stdin.readline().strip() 9 | imap = lambda: map(int,input().split()); ilist = lambda: list(imap()) 10 | #------------------------------------------------------------------ 11 | sys.setrecursionlimit(10**6) 12 | mod = int(1e9+7) 13 | 14 | n = int(input()) 15 | p = ilist() 16 | inp = [['']*n for i in range(n)] 17 | 18 | q = deque() 19 | st = set() 20 | src = set() 21 | for i in range(n): 22 | a = [x-1 for x in imap()] 23 | for j in range(n): 24 | inp[i][j] = (a[2*j], a[2*j+1]) 25 | if inp[i][j]!=(i,j): 26 | x,y = inp[i][j] 27 | src.add((x,y,(x,y))) 28 | st.add((x,y)) 29 | sym = "ULDR" 30 | rSym = "DRUL" 31 | dirs = [[-1,0],[0,-1],[1,0],[0,1]] 32 | q = deque(src) 33 | res = [['']*n for i in range(n)] 34 | while q: 35 | i,j,pr = q.popleft() 36 | for idx,[dx,dy] in enumerate(dirs): 37 | x,y = i+dx,j+dy 38 | if 0<=xN and j>N: break 132 | x,y =decomp[i],decomp[j] 133 | dif = [y[0]-x[0],y[1]-x[1]] 134 | if dif in dirs: 135 | idx = dirs.index(dif) 136 | res[x[0]][x[1]] = sym[idx] 137 | res[y[0]][y[1]] = rSym[idx] 138 | else: 139 | print(-1) 140 | exit() 141 | cnt = 0 142 | cost = 0 143 | for i in range(n): 144 | for j in range(n): 145 | if res[i][j] in "ULDR": 146 | cost+=p[sym.index(res[i][j])] 147 | cnt+=1 148 | def check(inp, res, n): 149 | def dfs(i,j, vis): 150 | dx,dy = dirs[sym.index(res[i][j])] 151 | x,y = i+dx,j+dy 152 | if 0<=x findCycledToItselfCells(Cell[][] matrix) { 45 | List cells = new ArrayList<>(); 46 | for (Cell[] row : matrix) { 47 | for (Cell cell : row) { 48 | if (cell.row == cell.endCycleRow && cell.col == cell.endCycleCol) { 49 | cells.add(cell); 50 | } 51 | } 52 | } 53 | return cells; 54 | } 55 | 56 | private static Cell leftNeighbour(Cell[][] matrix, Cell c) { 57 | return c.col > 0 ? matrix[c.row][c.col - 1] : null; 58 | } 59 | 60 | private static Cell rightNeighbour(Cell[][] matrix, Cell c) { 61 | return c.col < matrix.length - 1 ? matrix[c.row][c.col + 1] : null; 62 | } 63 | 64 | private static Cell upNeighbour(Cell[][] matrix, Cell c) { 65 | return c.row > 0 ? matrix[c.row - 1][c.col] : null; 66 | } 67 | 68 | private static Cell downNeighbour(Cell[][] matrix, Cell c) { 69 | return c.row < matrix.length - 1 ? matrix[c.row + 1][c.col] : null; 70 | } 71 | 72 | private static void joinSelfCycled(Cell[][] matrix, List cells, long pu, long pd, long pl, long pr) { 73 | boolean preferHorizontalJoin = pl + pr <= pu + pd; 74 | 75 | Set cellSet = new HashSet<>(cells); 76 | 77 | boolean removeAnyAdjacent = false; 78 | while (true) { 79 | int singleNeighbourRemoved = 0; 80 | 81 | for (Cell c : new ArrayList<>(cellSet)) { 82 | if (c.direction != null) continue; 83 | 84 | int neighboursCnt = 0; 85 | 86 | Cell left = leftNeighbour(matrix, c); 87 | if (left != null && cellSet.contains(left) && left.direction == null) { 88 | ++neighboursCnt; 89 | } else left = null; 90 | 91 | Cell right = rightNeighbour(matrix, c); 92 | if (right != null && cellSet.contains(right) && right.direction == null) { 93 | ++neighboursCnt; 94 | } else right = null; 95 | 96 | Cell up = upNeighbour(matrix, c); 97 | if (up != null && cellSet.contains(up) && up.direction == null) { 98 | ++neighboursCnt; 99 | } else up = null; 100 | 101 | Cell down = downNeighbour(matrix, c); 102 | if (down != null && cellSet.contains(down) && down.direction == null) { 103 | ++neighboursCnt; 104 | } else down = null; 105 | 106 | if (neighboursCnt == 0) return; 107 | 108 | if (neighboursCnt == 1) { 109 | if (left != null) { 110 | left.direction = Direction.R; 111 | c.direction = Direction.L; 112 | cellSet.remove(left); 113 | } else if (right != null) { 114 | right.direction = Direction.L; 115 | c.direction = Direction.R; 116 | cellSet.remove(right); 117 | } else if (up != null) { 118 | up.direction = Direction.D; 119 | c.direction = Direction.U; 120 | cellSet.remove(up); 121 | } else { 122 | down.direction = Direction.U; 123 | c.direction = Direction.D; 124 | cellSet.remove(down); 125 | } 126 | 127 | ++singleNeighbourRemoved; 128 | cellSet.remove(c); 129 | } 130 | } 131 | 132 | if (singleNeighbourRemoved > 0) continue; 133 | 134 | int cellsJoinedCnt = 0; 135 | for (Cell c : new ArrayList<>(cellSet)) { 136 | if (c.direction != null) continue; 137 | 138 | // removing from top-left corner 139 | Cell up = upNeighbour(matrix, c); 140 | Cell left = leftNeighbour(matrix, c); 141 | if ((up == null || !cellSet.contains(up)) && (left == null || !cellSet.contains(left))) { 142 | if (preferHorizontalJoin) { 143 | Cell right = rightNeighbour(matrix, c); 144 | if (right != null && cellSet.contains(right)) { 145 | Cell rightUp = upNeighbour(matrix, right); 146 | Cell rightDown = downNeighbour(matrix, right); 147 | if ((rightUp == null || !cellSet.contains(rightUp)) && (rightDown != null && cellSet.contains(rightDown)) || removeAnyAdjacent) { 148 | c.direction = Direction.R; 149 | right.direction = Direction.L; 150 | ++cellsJoinedCnt; 151 | cellSet.remove(c); 152 | cellSet.remove(right); 153 | removeAnyAdjacent = false; 154 | break; 155 | } 156 | } 157 | } else { 158 | Cell down = downNeighbour(matrix, c); 159 | if (down != null && cellSet.contains(down)) { 160 | Cell downLeft = leftNeighbour(matrix, down); 161 | Cell downRight = rightNeighbour(matrix, down); 162 | if ((downLeft == null || !cellSet.contains(downLeft)) && (downRight != null && cellSet.contains(downRight)) || removeAnyAdjacent) { 163 | c.direction = Direction.D; 164 | down.direction = Direction.U; 165 | ++cellsJoinedCnt; 166 | cellSet.remove(c); 167 | cellSet.remove(down); 168 | removeAnyAdjacent = false; 169 | break; 170 | } 171 | } 172 | } 173 | } 174 | 175 | // removing from bottom-left corner 176 | Cell down = downNeighbour(matrix, c); 177 | if ((down == null || !cellSet.contains(down)) && (left == null || !cellSet.contains(left))) { 178 | if (preferHorizontalJoin) { 179 | Cell right = rightNeighbour(matrix, c); 180 | if (right != null && cellSet.contains(right)) { 181 | Cell rightUp = upNeighbour(matrix, right); 182 | Cell rightDown = downNeighbour(matrix, right); 183 | if ((rightDown == null || !cellSet.contains(rightDown)) && (rightUp != null && cellSet.contains(rightUp)) || removeAnyAdjacent) { 184 | c.direction = Direction.R; 185 | right.direction = Direction.L; 186 | ++cellsJoinedCnt; 187 | cellSet.remove(c); 188 | cellSet.remove(right); 189 | removeAnyAdjacent = false; 190 | break; 191 | } 192 | } 193 | } else { 194 | up = upNeighbour(matrix, c); 195 | if (up != null && cellSet.contains(up)) { 196 | Cell upLeft = leftNeighbour(matrix, up); 197 | Cell upRight = rightNeighbour(matrix, up); 198 | if ((upLeft == null || !cellSet.contains(upLeft)) && (upRight != null && cellSet.contains(upRight)) || removeAnyAdjacent) { 199 | c.direction = Direction.U; 200 | up.direction = Direction.D; 201 | ++cellsJoinedCnt; 202 | cellSet.remove(c); 203 | cellSet.remove(up); 204 | removeAnyAdjacent = false; 205 | break; 206 | } 207 | } 208 | } 209 | } 210 | 211 | // removing from top-right corner 212 | up = upNeighbour(matrix, c); 213 | Cell right = rightNeighbour(matrix, c); 214 | if ((up == null || !cellSet.contains(up)) && (right == null || !cellSet.contains(right))) { 215 | if (preferHorizontalJoin) { 216 | left = leftNeighbour(matrix, c); 217 | if (left != null && cellSet.contains(left)) { 218 | Cell leftUp = upNeighbour(matrix, left); 219 | Cell leftDown = downNeighbour(matrix, left); 220 | if ((leftUp == null || !cellSet.contains(leftUp)) && (leftDown != null && cellSet.contains(leftDown)) || removeAnyAdjacent) { 221 | c.direction = Direction.L; 222 | left.direction = Direction.R; 223 | ++cellsJoinedCnt; 224 | cellSet.remove(c); 225 | cellSet.remove(left); 226 | removeAnyAdjacent = false; 227 | break; 228 | } 229 | } 230 | } else { 231 | down = downNeighbour(matrix, c); 232 | if (down != null && cellSet.contains(down)) { 233 | Cell downLeft = leftNeighbour(matrix, down); 234 | Cell downRight = rightNeighbour(matrix, down); 235 | if ((downRight == null || !cellSet.contains(downRight)) && (downLeft != null && cellSet.contains(downLeft)) || removeAnyAdjacent) { 236 | c.direction = Direction.D; 237 | down.direction = Direction.U; 238 | ++cellsJoinedCnt; 239 | cellSet.remove(c); 240 | cellSet.remove(down); 241 | removeAnyAdjacent = false; 242 | break; 243 | } 244 | } 245 | } 246 | } 247 | 248 | // removing from bottom-right corner 249 | down = downNeighbour(matrix, c); 250 | if ((down == null || !cellSet.contains(down)) && (right == null || !cellSet.contains(right))) { 251 | if (preferHorizontalJoin) { 252 | left = rightNeighbour(matrix, c); 253 | if (left != null && cellSet.contains(left)) { 254 | Cell leftUp = upNeighbour(matrix, left); 255 | Cell leftDown = downNeighbour(matrix, left); 256 | if ((leftDown == null || !cellSet.contains(leftDown)) && (leftUp != null && cellSet.contains(leftUp)) || removeAnyAdjacent) { 257 | c.direction = Direction.L; 258 | left.direction = Direction.R; 259 | ++cellsJoinedCnt; 260 | cellSet.remove(c); 261 | cellSet.remove(left); 262 | removeAnyAdjacent = false; 263 | break; 264 | } 265 | } 266 | } else { 267 | up = upNeighbour(matrix, c); 268 | if (up != null && cellSet.contains(up)) { 269 | Cell upLeft = leftNeighbour(matrix, up); 270 | Cell upRight = rightNeighbour(matrix, up); 271 | if ((upRight == null || !cellSet.contains(upRight)) && (upLeft != null && cellSet.contains(upLeft))) { 272 | c.direction = Direction.U; 273 | up.direction = Direction.D; 274 | ++cellsJoinedCnt; 275 | cellSet.remove(c); 276 | cellSet.remove(up); 277 | removeAnyAdjacent = false; 278 | break; 279 | } 280 | } 281 | } 282 | } 283 | } 284 | 285 | if (cellsJoinedCnt == 0) { 286 | if (!removeAnyAdjacent) { 287 | removeAnyAdjacent = true; 288 | } else { 289 | return; 290 | } 291 | } 292 | } 293 | } 294 | 295 | private static long countCost(Cell[][] matrix, long pu, long pd, long pl, long pr) { 296 | long result = 0; 297 | for (Cell[] row : matrix) { 298 | for (Cell cell : row) { 299 | if (cell.direction == null) return -1; 300 | switch (cell.direction) { 301 | case D: 302 | result += pd; 303 | break; 304 | case L: 305 | result += pl; 306 | break; 307 | case R: 308 | result += pr; 309 | break; 310 | case U: 311 | result += pu; 312 | break; 313 | } 314 | } 315 | } 316 | 317 | return result; 318 | } 319 | 320 | private static boolean sameCycle(Cell c1, Cell c2) { 321 | return c1.endCycleRow == c2.endCycleRow && c1.endCycleCol == c2.endCycleCol; 322 | } 323 | 324 | private static class Path implements Comparable { 325 | final LinkedHashSet visitedCells; 326 | final List directions; 327 | final Cell lastCell; 328 | final long totalSum; 329 | 330 | public Path(LinkedHashSet visitedCells, List directions, Cell lastCell, long totalSum) { 331 | this.visitedCells = visitedCells; 332 | this.directions = directions; 333 | this.lastCell = lastCell; 334 | this.totalSum = totalSum; 335 | } 336 | 337 | public Path move(Cell moveTo, Direction d, long cost) { 338 | LinkedHashSet newVisitedCells = new LinkedHashSet<>(this.visitedCells); 339 | newVisitedCells.add(moveTo); 340 | List newDirections = new ArrayList<>(this.directions); 341 | newDirections.add(d); 342 | return new Path(newVisitedCells, newDirections, moveTo, totalSum + cost); 343 | } 344 | 345 | public static Path forCell(Cell c) { 346 | LinkedHashSet visitedCells = new LinkedHashSet<>(); 347 | visitedCells.add(c); 348 | return new Path(visitedCells, new ArrayList<>(), c,0); 349 | } 350 | 351 | public int compareTo(Path p) { 352 | return compareResults(totalSum, directions.size(), p.totalSum, p.directions.size()); 353 | } 354 | } 355 | 356 | private static Cell chooseAnyNonVisited(Set cellsToJoin) { 357 | for (Cell c : cellsToJoin) { 358 | return c; 359 | } 360 | return null; 361 | } 362 | 363 | private static long gcd(long a, long b) { 364 | return b == 0 ? a : gcd(b, a % b); 365 | } 366 | 367 | private static long lcm(long a, long b) { 368 | return a * (b / gcd(a, b)); 369 | } 370 | 371 | private static int compareResults(long sum1, long count1, long sum2, long count2) { 372 | if (count1 == 0 || count2 == 0) return 0; 373 | long commonCount = lcm(count1, count2); 374 | return Long.compare(sum1 * (commonCount) / count1, sum2 * (commonCount) / count2); 375 | } 376 | 377 | private static void trySmartJoinCellToCycles(Cell[][] matrix, Cell cycleEndpoint, List cellsToJoin, long pu, long pd, long pl, long pr) { 378 | long minCost = Math.min(Math.min(pu, pd), Math.min(pl, pr)); 379 | Set cellsToJoinSet = new HashSet<>(cellsToJoin); 380 | 381 | 382 | while (!cellsToJoinSet.isEmpty()) { 383 | PriorityQueue paths = new PriorityQueue<>(); 384 | Path bestCandidate = null; 385 | 386 | for (Cell startCell : cellsToJoinSet) { 387 | paths.add(Path.forCell(startCell)); 388 | } 389 | 390 | while (!paths.isEmpty()) { 391 | Path path = paths.poll(); 392 | if (bestCandidate != null) { 393 | if (path.directions.size() > 0) { 394 | if (compareResults( 395 | bestCandidate.totalSum, 396 | bestCandidate.directions.size(), 397 | path.totalSum + (cellsToJoinSet.size() - path.directions.size()) * minCost, 398 | cellsToJoinSet.size()) <= 0) { 399 | continue; 400 | } 401 | } 402 | } 403 | 404 | if (path.lastCell.direction != null) { 405 | if (bestCandidate == null || path.compareTo(bestCandidate) < 0) { 406 | bestCandidate = path; 407 | } 408 | continue; 409 | } 410 | 411 | Cell up = upNeighbour(matrix, path.lastCell); 412 | if (up != null && sameCycle(up, cycleEndpoint) && !path.visitedCells.contains(up)) { 413 | paths.add(path.move(up, Direction.U, pu)); 414 | } 415 | 416 | Cell down = downNeighbour(matrix, path.lastCell); 417 | if (down != null && sameCycle(down, cycleEndpoint) && !path.visitedCells.contains(down)) { 418 | paths.add(path.move(down, Direction.D, pd)); 419 | } 420 | 421 | Cell left = leftNeighbour(matrix, path.lastCell); 422 | if (left != null && sameCycle(left, cycleEndpoint) && !path.visitedCells.contains(left)) { 423 | paths.add(path.move(left, Direction.L, pl)); 424 | } 425 | 426 | Cell right = rightNeighbour(matrix, path.lastCell); 427 | if (right != null && sameCycle(right, cycleEndpoint) && !path.visitedCells.contains(right)) { 428 | paths.add(path.move(right, Direction.R, pr)); 429 | } 430 | } 431 | 432 | if (bestCandidate == null) { 433 | return; 434 | // should never happen 435 | } 436 | 437 | List visitedCells = new ArrayList<>(bestCandidate.visitedCells); 438 | for (int i = 0; i < bestCandidate.directions.size(); ++i) { 439 | visitedCells.get(i).direction = bestCandidate.directions.get(i); 440 | cellsToJoinSet.remove(visitedCells.get(i)); 441 | } 442 | } 443 | } 444 | 445 | private static void joinCellsToCycles(Cell[][] matrix, List cycleEndpoints, long pu, long pd, long pl, long pr) { 446 | for (Cell cycleEndpoint : cycleEndpoints) { 447 | 448 | Set visited = new HashSet<>(); 449 | for (Cell[] row : matrix) { 450 | for (Cell c : row) { 451 | if (visited.contains(c) || !sameCycle(cycleEndpoint, c) || c.direction != null) { 452 | visited.add(c); 453 | continue; 454 | } 455 | 456 | Set cellsToJoin = new HashSet<>(); 457 | 458 | List currentCells = new ArrayList<>(); 459 | currentCells.add(c); 460 | cellsToJoin.add(c); 461 | visited.add(c); 462 | 463 | boolean targetMet = false; 464 | while (!currentCells.isEmpty()) { 465 | Set newCells = new HashSet<>(); 466 | for (Cell currentCell : currentCells) { 467 | List neighbours = new ArrayList<>(); 468 | 469 | Cell up = upNeighbour(matrix, currentCell); 470 | if (up != null && sameCycle(up, cycleEndpoint)) neighbours.add(up); 471 | Cell down = downNeighbour(matrix, currentCell); 472 | if (down != null && sameCycle(down, cycleEndpoint)) neighbours.add(down); 473 | Cell left = leftNeighbour(matrix, currentCell); 474 | if (left != null && sameCycle(left, cycleEndpoint)) neighbours.add(left); 475 | Cell right = rightNeighbour(matrix, currentCell); 476 | if (right != null && sameCycle(right, cycleEndpoint)) neighbours.add(right); 477 | 478 | for (Cell neighbour : neighbours) { 479 | if (neighbour.direction == null && !visited.contains(neighbour)) { 480 | newCells.add(neighbour); 481 | } 482 | if (neighbour == cycleEndpoint) targetMet = true; 483 | visited.add(neighbour); 484 | } 485 | } 486 | cellsToJoin.addAll(newCells); 487 | currentCells = new ArrayList<>(newCells); 488 | } 489 | 490 | if (!targetMet) return; 491 | 492 | if (!cellsToJoin.isEmpty()) { 493 | trySmartJoinCellToCycles(matrix, cycleEndpoint, new ArrayList<>(cellsToJoin), pu, pd, pl, pr); 494 | } 495 | } 496 | } 497 | 498 | 499 | } 500 | } 501 | 502 | static long solve(Cell[][] matrix, long pu, long pd, long pl, long pr) { 503 | List cycledToItselfCells = findCycledToItselfCells(matrix); 504 | joinSelfCycled(matrix, cycledToItselfCells, pu, pd, pl, pr); 505 | 506 | for (Cell c : cycledToItselfCells) { 507 | if (c.direction == null) return -1; 508 | } 509 | 510 | joinCellsToCycles(matrix, cycledToItselfCells, pu, pd, pl, pr); 511 | 512 | return countCost(matrix, pu, pd, pl, pr); 513 | } 514 | 515 | public static void main(String[] params) throws IOException { 516 | InputReader in = new InputReader(System.in); 517 | 518 | int n = in.readInt(); 519 | int pu = in.readInt(); 520 | int pl = in.readInt(); 521 | int pd = in.readInt(); 522 | int pr = in.readInt(); 523 | 524 | Cell[][] matrix = new Cell[n][n]; 525 | for (int i = 0; i < n; ++i) { 526 | int[] endpoints = new int[2 * n]; 527 | in.readIntArray(endpoints, 0, endpoints.length); 528 | for (int j = 0; j < n; j++) { 529 | matrix[i][j] = new Cell(i, j, endpoints[j * 2] - 1, endpoints[j * 2 + 1] - 1); 530 | } 531 | } 532 | 533 | long cost = solve(matrix, pu, pd, pl, pr); 534 | 535 | if (cost > 0) { 536 | printResult(matrix, cost); 537 | } else { 538 | System.out.println("-1"); 539 | } 540 | } 541 | 542 | private static void printResult(Cell[][] m, long cost) { 543 | System.out.println(cost); 544 | for (int i = 0; i < m.length; ++i) { 545 | for (int j = 0; j < m.length; ++j) { 546 | System.out.print(m[i][j].direction); 547 | } 548 | System.out.println(); 549 | } 550 | } 551 | 552 | static class InputReader { 553 | static final int bufferSize = 1 << 25; 554 | 555 | private char[] content; 556 | private int pos = 0; 557 | private int[] readTo = new int[1]; 558 | 559 | public InputReader(InputStream in) throws IOException { 560 | Reader charReader = new InputStreamReader(in); 561 | content = new char[bufferSize]; 562 | charReader.read(content, 0, content.length); 563 | charReader.close(); 564 | } 565 | 566 | public int readInt() { 567 | readIntArray(readTo, 0, 1); 568 | return readTo[0]; 569 | } 570 | 571 | public void readIntArray(int[] arr, int from, int length) { 572 | for (int i = from, k = 0; k < length; ++k, ++i) { 573 | while (pos < content.length && content[pos] < '0' && content[pos] != '+' && content[pos] != '-') ++pos; 574 | 575 | int num = 0; 576 | int sign = 1; 577 | if (content[pos] == '-') { 578 | sign = -1; 579 | ++pos; 580 | } else if (content[pos] == '+') ++pos; 581 | 582 | while (pos < content.length) { 583 | char ch = content[pos++]; 584 | if (ch < '0') { 585 | break; 586 | } else { 587 | int digit = ch - '0'; 588 | num = (num << 3) + (num << 1) + digit; 589 | } 590 | } 591 | arr[from++] = num * sign; 592 | } 593 | } 594 | } 595 | } -------------------------------------------------------------------------------- /Problem explanation.txt: -------------------------------------------------------------------------------- 1 | The problem is asking you to construct a Bash matrix based on a given set of notes. A Bash matrix is an N by N matrix where each cell contains one of the characters 'U', 'D', 'L', or 'R'. The goal is to find the smallest possible cost for the matrix that satisfies the given notes. 2 | 3 | The notes indicate the path Chef took in the matrix. He starts in a cell and follows the instructions in each cell until he either reaches a previously visited cell or leaves the matrix. The stopping cell is the first cell he visits twice during this process. 4 | 5 | The input consists of the matrix size N, followed by the costs for each character ('U', 'L', 'D', 'R'), and the coordinates for each cell in the matrix. The coordinates indicate the row and column of the cells that Chef visited in his path. 6 | 7 | The output should be the minimum cost of the Bash matrix and the matrix itself, represented as N+1 lines. Each line represents a row in the matrix. 8 | 9 | If it is not possible to construct a Bash matrix that satisfies the given notes, the output should be -1. -------------------------------------------------------------------------------- /Time Complexity.txt: -------------------------------------------------------------------------------- 1 | Here's a general breakdown of the time complexity for different parts of the code: 2 | 3 | 1. Reading Input: O(N^2) 4 | - The input consists of N lines, each containing 2N space-separated integers. 5 | - Reading these integers would take O(N^2) time. 6 | 7 | 2. Constructing the Bash Matrix: O(N^2) 8 | - The Bash matrix is an N by N matrix, so constructing it would take O(N^2) time. 9 | 10 | 3. Checking Validity of the Bash Matrix: O(N^2) 11 | - To check the validity of the Bash matrix, we need to simulate Chef's movement based on the instructions in each cell. 12 | - This would require traversing each cell of the matrix, resulting in a time complexity of O(N^2). 13 | 14 | 4. Finding the Minimum Cost: O(N) 15 | - To find the minimum cost, we need to iterate over each character in the Bash matrix and sum up the corresponding costs. 16 | - Since the Bash matrix has N rows and N columns, the total number of characters is N^2. 17 | - Thus, finding the minimum cost would take O(N^2) time. 18 | 19 | Overall, the dominant factor in the time complexity would be O(N^2) due to the simulation of Chef's movement and the finding of the minimum cost. The other parts, such as input reading and matrix construction, have a time complexity of O(N^2) as well but have a lesser impact on the overall complexity. --------------------------------------------------------------------------------