SRM527 Div1 Medium(450) P8XMatrixRecovery
頂点数が2Cの二部グラフを考える。rowsのi番目の列と、columnsのj番目の要素に、矛盾が無ければ、左側のi番目の点と右側のj番目の間に辺があるとする。この二部グラフに完全マッチが存在する時かつその時に限り、マトリックスが存在する。完全マッチは複数存在する場合があり、この問題では辞書順最小の答えを返す必要がある。そこで、左上の?から順に、マトリックスが存在するならば0を、そうでなければ1を割り当てていく。O(C5)。
#include <string> #include <vector> using namespace std; int R, C; // 最大流 int maxflow( vector<vector<int> > edge, int s=0, int t=-1 ) { int n = (int)edge.size(); if ( t<0 ) t = n-1; int f = 0; vector<vector<int> > F(n,vector<int>(n)); while(true) { vector<int> P(n,-1); P[s]=-2; vector<int> Q(1,s); while ( !Q.empty() && P[t]==-1 ) { int u = Q.back(); Q.pop_back(); for ( int v=0; v<n && P[t]==-1; v++ ) if ( P[v]==-1 && edge[u][v]-F[u][v]>0 ) P[v] = u, Q.push_back(v); } if ( P[t]==-1 ) break; int m = edge[P[t]][t]; for ( int v=P[t]; v!=s; v=P[v] ) m = min(m,edge[P[v]][v]-F[P[v]][v]); f += m; for ( int v=t; v!=s; v=P[v] ) F[P[v]][v] += m, F[v][P[v]] -= m; } return f; } // 二部グラフの最大マッチング int bipartite( vector<vector<bool> > edge ) { int n = (int)edge.size(); int m = (int)edge[0].size(); vector<vector<int> > E(n+m+2,vector<int>(n+m+2)); for ( int i=0; i<n; i++ ) E[0][i+1] = 1; for ( int i=0; i<n; i++ ) for ( int j=0; j<m; j++ ) if ( edge[i][j] ) E[i+1][j+n+1] = 1; for ( int i=0; i<m; i++ ) E[i+n+1][n+m+1] = 1; return maxflow(E); } bool valid( vector <string> rows, vector <string> columns ) { vector<vector<bool> > E( C, vector<bool>(C) ); for ( int i=0; i<C; i++ ) for ( int j=0; j<C; j++ ) { bool f = true; for ( int k=0; k<R&&f; k++ ) if ( rows[k][i]!='?' && columns[j][k]!='?' && rows[k][i]!=columns[j][k] ) f = false; E[i][j] = f; } return bipartite(E)==C; } class P8XMatrixRecovery{public: vector <string> solve( vector <string> rows, vector <string> columns ) { R = (int)rows.size(); C = (int)columns.size(); for ( int y=0; y<R; y++ ) for ( int x=0; x<C; x++ ) if ( rows[y][x]=='?' ) { rows[y][x]='0'; if ( !valid(rows,columns) ) rows[y][x]='1'; } return rows; }};