내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
이 질문은 2009년 ICPC 아시아지역대회 상하이지부에서 보낸 질문입니다.
꽃박람회에서는 m행 n열(m≤n)의 직사각형에 n종의 꽃을 배치하는 방법이 있는데, 각 행의 n개 셀에 배치된 꽃은 서로 다르며, 배치된 꽃은 서로 다릅니다. 각 열의 m개 셀도 서로 다릅니다. 이제 이 규칙에 따라 또 다른 꽃줄을 추가하고, k번째 배치 계획이 존재하지 않을 경우 -1을 출력합니다. ≤K≤ 200.
이분 그래프 + dfs 열거 가지치기, 아이디어는 이 기사에서 나왔습니다.블로그。
각 열에 배치할 수 있는 꽃의 수를 찾아 모서리를 연결한 다음 이분 그래프 매칭을 실행하여 완벽하게 일치하는지 확인합니다. 그렇지 않으면 배치할 수 없습니다. 이 이분 그래프 매칭을 실행하는 것은 헛되지 않으며 나중에 사용됩니다.
k번째 사전 순서가 필요하기 때문에 각 열에 배치할 수 있는 꽃을 나열해야 합니다. 여기서는 정리가 필요합니다. 현재 열거된 열이 j번째 열이고 후속 j+1부터 N번째 열이 일치할 수 없는 경우 정리할 수 있습니다.
#include <iostream>
#include <cstring>
using namespace std;
#define N 205
int g[N][N], f[N][N], c[N], px[N], py[N], vis[N], ans[N], p1[N], p2[N], m, n, k, clk; bool use[N];
bool dfs(int u, int pos = -1) {
if (u <= pos) return false;
vis[u] = clk;
for (int i=0, v; i<c[u]; ++i) if (py[v = g[u][i]] < 0 || (vis[py[v]]!=clk && dfs(py[v], pos))) {
px[u] = v; py[v] = u;
return true;
}
return false;
}
int max_match() {
memset(px, -1, sizeof(px)); memset(py, -1, sizeof(py)); memset(vis, -1, sizeof(vis));
int cc = 0;
for (int i=1; i<=n; ++i) if (px[i] < 0 && dfs(clk = i)) ++cc;
return cc;
}
bool ok(int u, int v) {
if (px[u] == v) return true;
int x = 0;
for (int i=1; i<=n; ++i) {
p1[i] = px[i]; p2[i] = py[i];
if (px[i] == v) if ((x = i) < u) return false;
}
px[x] = py[px[u]] = -1; px[u] = v; py[v] = u; ++clk;
if (dfs(x, u)) return true;
for (int i=1; i<=n; ++i) px[i] = p1[i], py[i] = p2[i];
return false;
}
bool find(int u) {
if (u > n) return ++m == k;
for (int i=0, v; i<c[u]; ++i) if (!use[v = g[u][i]] && ok(u, v)) {
use[v] = true; ans[u] = v;
if (find(u+1)) return true;
use[v] = false;
}
return false;
}
void solve () {
cin >> n >> m >> k;
for (int i=1; i<=m; ++i) for (int j=1; j<=n; ++j) cin >> f[i][j];
for (int i=1; i<=n; ++i) {
memset(vis, c[i] = 0, sizeof(vis));
for (int j=1; j<=m; ++j) vis[f[j][i]] = true;
for (int j=1; j<=n; ++j) if (!vis[j]) g[i][c[i]++] = j;
}
if (max_match() != n) {
cout << " -1" << endl;
return;
}
memset(use, m = 0, sizeof(use)); memset(vis, clk = 0, sizeof(vis));
if (find(1)) {
for (int i=1; i<=n; ++i) cout << ' ' << ans[i];
cout << endl;
} else cout << " -1" << endl;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t; cin >> t;
for (int k=1; k<=t; ++k) cout << "Case #" << k << ':', solve();
return 0;
}