DLX是一种相当神奇的数据结构,通常用于解决矩阵(多为稀疏矩阵)的 重复|精确 覆盖的问题。不过一般这类问题的难点是抽出转化关系,剩下的几乎就是套模板
#include<cstdio> #include<iostream> #include<string> #include<cstring> #include<algorithm> #include<cmath> #include<vector> using namespace std; typedef long long LL; const int MAXN = 65; const int MAXM = MAXN*MAXN*200; const int MAXD = 16; int n, m, day; int res[MAXN]; const int mmp[6][6] = { 0,0,0,0,0,0, 0,1,2,3,4,5, 0,0,6,7,8,9, 0,0,0,10,11,12, 0,0,0,0,13,14, 0,0,0,0,0,15 }; int tar[20][2]; struct DLX { int L[MAXM],R[MAXM],U[MAXM],D[MAXM]; int sz,row[MAXM],col[MAXM],S[MAXN*10],H[MAXN*20]; void del(int c) { L[R[c]]=L[c]; R[L[c]]=R[c]; for(int i=D[c]; i!=c; i=D[i]) for(int j=R[i]; j!=i; j=R[j]) U[D[j]]=U[j],D[U[j]]=D[j],--S[col[j]]; } void add(int c) { R[L[c]]=L[R[c]]=c; for(int i=U[c]; i!=c; i=U[i]) for(int j=L[i]; j!=i; j=L[j]) ++S[col[U[D[j]]=D[U[j]]=j]]; } void init(int m) { for(int i=0; i<=m; i++) { S[i]=0; L[i]=i-1; R[i]=i+1; U[i]=D[i]=i; } L[0]=m; R[m]=0; sz=m+1; memset(H,-1,sizeof(H)); } void link(int x,int y) { ++S[col[sz]=y]; row[sz]=x; D[sz]=D[y]; U[D[y]]=sz; U[sz]=y; D[y]=sz; if(H[x]<0)H[x]=L[sz]=R[sz]=sz; else { R[sz]=R[H[x]]; L[R[H[x]]]=sz; L[sz]=H[x]; R[H[x]]=sz; } sz++; } bool dfs() { if(!R[0]) return 1; int c=R[0]; for(int i=R[0]; i; i=R[i])if(S[c]>S[i])c=i; del(c); for(int i=D[c]; i!=c; i=D[i]) { res[(row[i]-1)/MAXD + 1] = i; for(int j=R[i]; j!=i; j=R[j])del(col[j]); if(dfs()) return 1; for(int j=L[i]; j!=i; j=L[j])add(col[j]); res[(row[i]-1)/MAXD + 1] = 0; } add(c); return 0; } void cal() { if (dfs()) { for (int i = 1, j; i<= n; ++i) { j = (row[res[i]]-1)%MAXD + 1; printf("%d %d\n", tar[j][0], tar[j][1]); } } else puts("No solution"); puts(""); } } dlx; int edge[MAXN][MAXN]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif for (int i = 1; i<= 5; ++i) for (int j = i; j<= 5; ++j) tar[mmp[i][j]][0] = i, tar[mmp[i][j]][1] = j; tar[MAXD][0] = 0; tar[MAXD][1] = 0; while (scanf("%d%d%d", &n, &m, &day) != EOF) { dlx.init(n*day+n); memset(res, 0, sizeof res); memset(edge, 0, sizeof edge); for (int i = 1; i<= n; ++i) edge[i][i] = 1; for (int i = 0, u, v; i< m; ++i) { scanf("%d%d", &u, &v); edge[u][v] = edge[v][u] = 1; } for (int i = 1, b, e, da; i<= n; ++i) { scanf("%d%d", &b, &e); da = (i-1)*MAXD; dlx.link(da+MAXD, n*day+i); for (int q = b; q<= e; ++q) { for (int w = q; w<= e; ++w) { dlx.link(mmp[q][w]+da, n*day+i); for (int k = q; k<= w; ++k) { for (int o = 1; o<= n; ++o) if (edge[i][o]) { dlx.link(mmp[q][w]+da, (o-1)*day+k); } } } } } dlx.cal(); } return 0; }
hdu 5046 Airport
二分+DLX#include<cstdio> #include<iostream> #include<string> #include<cstring> #include<algorithm> #include<cmath> #include<map> using namespace std; typedef long long LL; const int MAXN = 65; const int MAXM = MAXN*MAXN; int n, m; int vis[MAXN], nlen; LL dis[MAXN][MAXN], len[MAXM]; inline LL mabs(LL a) { return a<0?-a:a; } struct _point { LL x, y; LL gt_dis(const _point & a) { return mabs(x-a.x) + mabs(y-a.y); } }pt[MAXN]; struct _node { int U[MAXM], D[MAXM], L[MAXM], R[MAXM], COL[MAXM], ROW[MAXM]; int H[MAXN], S[MAXN]; int sz, ans; void init() { memset(H, -1, sizeof H); for (int i = 0; i<= n; ++i) { S[i] = 0; U[i] = D[i] = i; L[i+1] = i; R[i] = i+1; } R[n] = 0; sz = n+1; } void link(int r, int c) { ++S[c]; COL[sz] = c; ROW[sz] = r; U[sz] = U[c]; D[sz] = c; U[c] = sz; D[U[sz]] = sz; if (H[r] == -1) H[r] = L[sz] = R[sz] = sz; else { L[sz] = L[H[r]]; R[sz] = H[r]; R[L[sz]] = sz; L[R[sz]] = sz; } ++sz; } void remv(int dx) { for (int i = D[dx]; i!=dx; i = D[i]) L[R[i]] = L[i], R[L[i]] = R[i]; } void resum(int dx) { for (int i = D[dx]; i!=dx; i = D[i]) L[R[i]] = R[L[i]] = i; } int h() { int cnt = 0; memset(vis, 0, sizeof vis); for (int i = R[0]; i; i = R[i]) { if (vis[i]) continue; ++cnt; for (int j = D[i]; j!=i; j=D[j]) { for (int k = R[j]; k!=j; k=R[k]) vis[COL[k]] = 1; } } return cnt; } void dance(int k) { int mn, dx; if (ans || k + h() > m ) return ; if (!R[0]) { ans = 1; return; } mn = MAXN; for (int i = R[0]; i; i = R[i]) if (mn > S[i]) mn = S[i], dx = i; for (int i = D[dx]; i != dx; i = D[i]) { remv(i); for (int j = R[i]; j != i; j = R[j]) remv(j); dance(k+1); for (int j = R[i]; j != i; j = R[j]) resum(j); resum(i); } } int cal(LL mxlen) { init(); for (int i = 1; i<= n; ++i) { for (int j = 1; j<= n; ++j) { if (dis[i][j] <= mxlen) link(i, j); } } ans = 0; dance(0); return ans; } }node; LL solve() { int bg = 0, ed = nlen-1, mm; LL dd; while (bg < ed) { mm = (bg+ed)>>1; dd = len[mm]; if (node.cal(dd)) ed = mm; else bg = mm+1; } return len[bg]; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif int t; scanf("%d", &t); for (int _ = 1; _ <= t; ++_) { printf("Case #%d: ", _); scanf("%d%d", &n, &m); for (int i = 1; i<= n; ++i) scanf("%I64d%I64d", &pt[i].x, &pt[i].y); nlen = 0; for (int i = 1; i<= n; ++i) for (int j = i; j<= n; ++j) dis[i][j] = dis[j][i] = pt[i].gt_dis(pt[j]), len[nlen++] = dis[i][j]; sort(len, len+nlen); nlen = unique(len, len+nlen) - len; printf("%I64d\n", solve()); } return 0; }
hdu 4735 Little Wish~ lyrical step~
在一棵无向有边权的树上,每个节点表示男或女,可挑选任意两点交换,是每个女的距离D之内至少有一个男的,求交换的最小次数。明显同性之间没有交换的必要,可以用DLX枚举可能的最后状态,找出与最初状态差别最小的#include<cstdio> #include<iostream> #include<string> #include<cstring> #include<algorithm> #include<cmath> #include<map> using namespace std; const int MAXN = 55; const int MAXM = MAXN*MAXN; int n, m; int vis[MAXN]; int dis[MAXN][MAXN], boy[MAXN], boys; struct _node { int U[MAXM], D[MAXM], L[MAXM], R[MAXM], COL[MAXM], ROW[MAXM]; int H[MAXN], S[MAXN]; int sz, ans; void init() { memset(H, -1, sizeof H); for (int i = 0; i<= n; ++i) { S[i] = 0; U[i] = D[i] = i; L[i+1] = i; R[i] = i+1; } R[n] = 0; sz = n+1; } void link(int r, int c) { ++S[c]; COL[sz] = c; ROW[sz] = r; U[sz] = U[c]; D[sz] = c; U[c] = sz; D[U[sz]] = sz; if (H[r] == -1) H[r] = L[sz] = R[sz] = sz; else { L[sz] = L[H[r]]; R[sz] = H[r]; R[L[sz]] = sz; L[R[sz]] = sz; } ++sz; } void remv(int dx) { for (int i = D[dx]; i!=dx; i = D[i]) L[R[i]] = L[i], R[L[i]] = R[i]; } void resum(int dx) { for (int i = D[dx]; i!=dx; i = D[i]) L[R[i]] = R[L[i]] = i; } int h() { int cnt = 0; memset(vis, 0, sizeof vis); for (int i = R[0]; i; i = R[i]) { if (vis[i]) continue; ++cnt; for (int j = D[i]; j!=i; j=D[j]) { for (int k = R[j]; k!=j; k=R[k]) vis[COL[k]] = 1; } } return cnt; } void dance(int k, int p) { int mn, dx; if (p >= ans || p > boys || k + h() > boys) return ; if (!R[0]) { ans = p; return; } mn = MAXN; for (int i = R[0]; i; i = R[i]) if (mn > S[i]) mn = S[i], dx = i; for (int i = D[dx]; i != dx; i = D[i]) { remv(i); for (int j = R[i]; j != i; j = R[j]) remv(j); dance(k+1, p + !boy[ROW[i]]); for (int j = R[i]; j != i; j = R[j]) resum(j); resum(i); } } int cal() { for (int i = 1; i<= n; ++i) { for (int j = 1; j<= n; ++j) { if (dis[i][j] <= m) link(i, j); } } ans = 100000000; dance(0, 0); return ans>boys?-1:ans; } }node; void init_local() { memset(dis, 0x3f, sizeof dis); boys = 0; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif int t; scanf("%d", &t); for (int _ = 1; _ <= t; ++_) { printf("Case #%d: ", _); scanf("%d%d", &n, &m); init_local(); node.init(); for (int i = 1; i<= n; ++i) scanf("%d", boy+i), boys += boy[i], dis[i][i] = 0; for (int i = 1, a, b, c; i< n; ++i) { scanf("%d%d%d", &a, &b, &c); dis[a][b] = dis[b][a] = c; } for (int k = 1; k<= n; ++k) for (int i = 1; i<= n; ++i) for (int j = 1; j<= n; ++j) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); printf("%d\n", node.cal()); } return 0; }
hdu 3498 whosyourdaddy
比较裸的重复覆盖问题#include<cstdio> #include<iostream> #include<string> #include<cstring> #include<algorithm> #include<cmath> #include<map> using namespace std; const int MAXN = 60; const int MAXM = MAXN*MAXN; int n, m; int mmp[MAXN][MAXN], vis[MAXN]; struct _node { int U[MAXM], D[MAXM], L[MAXM], R[MAXM], C[MAXM]; int H[MAXN], S[MAXN]; int sz, ans; void init() { memset(mmp, 0, sizeof mmp); memset(H, -1, sizeof H); for (int i = 0; i<= n; ++i) { S[i] = 0; U[i] = D[i] = i; L[i+1] = i; R[i] = i+1; } R[n] = 0; sz = n+1; } void link(int r, int c) { ++S[c]; C[sz] = c; U[sz] = U[c]; D[sz] = c; U[c] = sz; D[U[sz]] = sz; if (H[r] == -1) H[r] = L[sz] = R[sz] = sz; else { L[sz] = L[H[r]]; R[sz] = H[r]; R[L[sz]] = sz; L[R[sz]] = sz; } ++sz; } void remv(int dx) { for (int i = D[dx]; i!=dx; i = D[i]) L[R[i]] = L[i], R[L[i]] = R[i]; } void resum(int dx) { for (int i = D[dx]; i!=dx; i = D[i]) L[R[i]] = R[L[i]] = i; } int h() { int cnt = 0; memset(vis, 0, sizeof vis); for (int i = R[0]; i; i = R[i]) { if (vis[i]) continue; ++cnt; for (int j = D[i]; j!=i; j=D[j]) { for (int k = R[j]; k!=j; k=R[k]) vis[C[k]] = 1; } } return cnt; } void dance(int k) { int mn, dx; if (k + h() >= ans) return ; if (!R[0]) { if (k < ans) ans = k; return; } mn = MAXN; for (int i = R[0]; i; i = R[i]) if (mn > S[i]) mn = S[i], dx = i; for (int i = D[dx]; i != dx; i = D[i]) { remv(i); for (int j = R[i]; j != i; j = R[j]) remv(j); dance(k+1); for (int j = R[i]; j != i; j = R[j]) resum(j); resum(i); } } int cal() { for (int i = 1; i<= n; ++i) { for (int j = 1; j<= n; ++j) { if (mmp[i][j] || i == j) link(i, j); } } ans = n; dance(0); return ans; } }node; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif while (scanf("%d%d", &n, &m) != EOF) { node.init(); for (int i = 0, a, b; i< m; ++i) { scanf("%d%d", &a, &b); mmp[a][b] = mmp[b][a] = 1; } printf("%d\n", node.cal()); } return 0; }
hdu 3111 Sudoku
把每个点的覆盖、横 纵轴上数字的覆盖、每个块的覆盖 状态罗列出来共有 9*9*4 种状态作为横轴,用每个点填充数字1-9共 9*9*9 种状态作为纵轴
#include<cstdio> #include<iostream> #include<string> #include<cstring> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int MAXC = 330; const int MAXR = 735; const int MAXM = MAXR*MAXC; int res[100], check[MAXC], nr; struct DLX { int L[MAXM],R[MAXM],U[MAXM],D[MAXM]; int sz,row[MAXM],col[MAXM],S[MAXC],H[MAXR]; void del(int c) { L[R[c]]=L[c]; R[L[c]]=R[c]; for(int i=D[c]; i!=c; i=D[i]) for(int j=R[i]; j!=i; j=R[j]) U[D[j]]=U[j],D[U[j]]=D[j],--S[col[j]]; } void add(int c) { R[L[c]]=L[R[c]]=c; for(int i=U[c]; i!=c; i=U[i]) for(int j=L[i]; j!=i; j=L[j]) ++S[col[U[D[j]]=D[U[j]]=j]]; } void init(int m) { for(int i=0; i<=m; i++) { S[i]=0; L[i]=i-1; R[i]=i+1; U[i]=D[i]=i; } L[0]=m; R[m]=0; sz=m+1; memset(H,-1,sizeof(H)); } void link(int x,int y) { ++S[col[sz]=y]; row[sz]=x; D[sz]=D[y]; U[D[y]]=sz; U[sz]=y; D[y]=sz; if(H[x]<0)H[x]=L[sz]=R[sz]=sz; else { R[sz]=R[H[x]]; L[R[H[x]]]=sz; L[sz]=H[x]; R[H[x]]=sz; } sz++; } bool dfs() { if(!R[0]) return 1; int c=R[0]; for(int i=R[0]; i; i=R[i])if(S[c]>S[i])c=i; del(c); for(int i=D[c]; i!=c; i=D[i]) { res[nr++] = i; for(int j=R[i]; j!=i; j=R[j])del(col[j]); if(dfs()) return 1; for(int j=L[i]; j!=i; j=L[j])add(col[j]); --nr; } add(c); return 0; } } dlx; char mmp[20][20]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif int T, ans; scanf("%d", &T); for (int t = 0; t< T; ++t) { ans = 1; nr = 0; memset(check, 0, sizeof check); if (t) scanf("%s", mmp[0]), printf("---\n"); dlx.init(9*9*4); memset(res, -1, sizeof res); for (int i = 1, k = 1, p, u, r, c; i<= 9; ++i) { scanf("%s", mmp[i]+1); for (int j = 1; j<= 9; ++j, ++k) if (mmp[i][j] != '?') { p = mmp[i][j] - '0'; r = (i-1)/3+1; c = (j-1)/3+1; c = (r-1)*3+c; dlx.link(u=(k-1)*9+p, k); dlx.link(u, r=(i-1)*9+p+81); if (check[r]) ans = 0; check[r] = 1; dlx.link(u, r=(j-1)*9+p+162); if (check[r]) ans = 0; check[r] = 1; dlx.link(u, r=(c-1)*9+p+243); if (check[r]) ans = 0; check[r] = 1; } else { for (p = 1; p <= 9; ++p) { r = (i-1)/3+1; c = (j-1)/3+1; c = (r-1)*3+c; dlx.link(u=(k-1)*9+p, k); dlx.link(u, (i-1)*9+p+81); dlx.link(u, (j-1)*9+p+162); dlx.link(u, (c-1)*9+p+243); } } } if (!ans || !dlx.dfs()) printf("impossible\n"); else { for (int i = 0, o; i< nr; ++i) { o = dlx.row[res[i]]; int r = (o-1)/81+1; int c = (o-1)%81/9+1; int p = (o-1)%9+1; mmp[r][c] = '0'+p; } for (int i = 1; i<= 9; ++i) printf("%s\n", mmp[i]+1); } } return 0; }