【Dancing Link专题】解题报告
DLX用于优化精确覆盖问题,由于普通的DFS暴力搜索会超时,DLX是一个很强有力的优化手段,其实DLX的原理很简单,就是利用十字链表的快速删除和恢复特点,在DFS时删除一些行和列以减小查找规模,使得搜索深度越深而越小,然后回溯继续查找。具体资料可【点击这里】。
精确覆盖问题(补充):具体一点儿就是给你一个0-1矩阵,要你找出一些行,使得每一列都有且只有一个1。
HUST 1017 Exact cover
入门必做,测试模板。
#include <stdio.h>
#include <string.h> const int N = ;
const int M = ;
const int head = ;
const int oo = 0x3fffffff; int U[M], D[M], L[M], R[M];
int S[N], O[M], H[M];
int X[M], Y[M]; // arr X record the row id and Y the column
int n, m, num, sz, len; void init(int n, int m)
{
for(int i = ; i <= m; i++)
{
U[i] = D[i] = i;
L[i+] = i;
R[i] = i+;
S[i] = ;
}
R[m] = ;
L[] = m;
sz = m+;
} void ins(int r, int c)
{
S[c]++;
// 纵向插入
D[U[c]] = sz;
U[sz] = U[c];
D[sz] = c;
U[c] = sz;
X[sz] = c;
Y[sz] = r;
// 横向插入
if(H[r] == -)
H[r] = L[sz] = R[sz] = sz;
else
{
R[L[H[r]]] = sz;
L[sz] = L[H[r]];
R[sz] = H[r];
L[H[r]] = sz;
}
sz++;
} void remove(const int &c)
{
// remove column c and all row i that A[i][c] == 1
L[R[c]] = L[c];
R[L[c]] = R[c];
// remove column c
for(int i = D[c]; i != c; i = D[i])
{
// remove i that A[i][c] == 1
for(int j = R[i]; j != i; j = R[j])
{
U[D[j]] = U[j];
D[U[j]] = D[j];
--S[X[j]]; // decrease the count of column C[j];
}
}
} void resume(const int &c)
{
// 恢复行
for(int i = D[c]; i != c; i = D[i])
{
for(int j = R[i]; j != i; j = R[j])
{
++S[X[j]];
U[D[j]] = j;
D[U[j]] = j;
}
}
// 恢复一整列
L[R[c]] = c;
R[L[c]] = c;
} bool dfs(const int &k)
{
if(R[head] == head)
{
len = k;
return true;
}
int s(oo), c;
for(int t = R[head]; t != head; t = R[t])
{
// select the column c which has the fewest number of element
if(S[t] < s)
{
s = S[t];
c = t;
}
}
remove(c);
for(int i = D[c]; i != c; i = D[i])
{
O[k] = Y[i]; // record the answer
for(int j = R[i]; j != i; j = R[j])
remove(X[j]);
if(dfs(k+))
return true;
for(int j = R[i]; j != i; j = R[j])
resume(X[j]);
}
resume(c);
return false;
} int main()
{
int c;
while(scanf("%d%d", &n, &m) != EOF)
{
init(n, m);
for(int i = ; i <= n; i++)
{
scanf("%d", &num);
H[i] = -;
for(int j = ; j <= num; j++)
{
scanf("%d", &c);
ins(i, c);
}
}
if(dfs())
{
printf("%d", len);
for(int i = ; i < len; i++)
printf(" %d", O[i]);
putchar('\n');
}
else
puts("NO");
}
return ;
}
POJ 3740 Easy Finding
和上一题差不多,甚至还更简单。
#include <stdio.h>
#include <string.h> const int N = ;
const int M = ;
const int head = ;
const int oo = 0x3fffffff; int U[M], D[M], L[M], R[M];
int S[N], O[M], H[M];
int X[M], Y[M];
int n, m, num, sz, len; void init(int n, int m)
{
for(int i = ; i <= m; i++)
{
U[i] = D[i] = i;
L[i+] = i;
R[i] = i+;
S[i] = ;
}
R[m] = ;
L[] = m;
sz = m+;
} void ins(int r, int c)
{
S[c]++; D[U[c]] = sz;
U[sz] = U[c];
D[sz] = c;
U[c] = sz;
X[sz] = c;
Y[sz] = r; if(H[r] == -)
H[r] = L[sz] = R[sz] = sz;
else
{
R[L[H[r]]] = sz;
L[sz] = L[H[r]];
R[sz] = H[r];
L[H[r]] = sz;
}
sz++;
} void remove(const 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[X[j]];column C[j];
}
}
} void resume(const int &c)
{
for(int i = D[c]; i != c; i = D[i])
{
for(int j = R[i]; j != i; j = R[j])
{
++S[X[j]];
U[D[j]] = j;
D[U[j]] = j;
}
}
L[R[c]] = c;
R[L[c]] = c;
} bool dfs(const int &k)
{
if(R[head] == head)
{
len = k;
return true;
}
int s(oo), c;
for(int t = R[head]; t != head; t = R[t])
{
if(S[t] < s)
{
s = S[t];
c = t;
}
}
remove(c);
for(int i = D[c]; i != c; i = D[i])
{
O[k] = Y[i]; // record the answer
for(int j = R[i]; j != i; j = R[j])
remove(X[j]);
if(dfs(k+))
return true;
for(int j = R[i]; j != i; j = R[j])
resume(X[j]);
}
resume(c);
return false;
} int main()
{
int c;
while(scanf("%d%d", &n, &m) != EOF)
{
init(n, m);
for(int i = ; i <= n; i++)
{
H[i] = -;
for(int j = ; j <= m; j++)
{
scanf("%d", &c);
if(c == )
ins(i, j);
}
}
if(dfs())
puts("Yes, I found it");
else
puts("It is impossible");
}
return ;
}
ZOJ 3209 Treasure Map
将二维变一维,离散化,每个点坐标对应一列,DLX一共有p行n*m列,直接构造即可。(ZOJ里面没有RE吗?我数组开小了返回TLE,很郁闷)。
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N = ;
const int M = ;
const int head = ;
const int oo = 0x3f3f3f3f; int U[M], D[M], L[M], R[M];
int S[N], O[M], H[M];
int X[M], Y[M];
int n, m, num, sz, len, p;
int ans; void init(int n, int m)
{
for(int i = ; i <= m; i++)
{
U[i] = D[i] = i;
L[i+] = i;
R[i] = i+;
S[i] = ;
}
R[m] = ;
L[] = m;
sz = m+;
} void ins(int r, int c)
{
S[c]++;
D[U[c]] = sz;
U[sz] = U[c];
D[sz] = c;
U[c] = sz;
X[sz] = c;
Y[sz] = r;
if(H[r] == -)
H[r] = L[sz] = R[sz] = sz;
else
{
R[L[H[r]]] = sz;
L[sz] = L[H[r]];
R[sz] = H[r];
L[H[r]] = sz;
}
sz++;
} void remove(const 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[X[j]];
}
}
} void resume(const int &c)
{
for(int i = D[c]; i != c; i = D[i])
{
for(int j = R[i]; j != i; j = R[j])
{
++S[X[j]];
U[D[j]] = j;
D[U[j]] = j;
}
}
L[R[c]] = c;
R[L[c]] = c;
} void dfs(const int &k)
{
if(k >= ans) return ;
if(R[head] == head)
{
ans = std::min(ans, k);
return;
}
int s(oo), c;
for(int t = R[head]; t != head; t = R[t])
{
if(S[t] < s)
{
s = S[t];
c = t;
}
}
remove(c);
for(int i = D[c]; i != c; i = D[i])
{
O[k] = Y[i];
for(int j = R[i]; j != i; j = R[j])
remove(X[j]);
dfs(k+);
for(int j = L[i]; j != i; j = L[j])
resume(X[j]);
}
resume(c);
} int main()
{
int x1, y1, x2, y2;
int cas;
scanf("%d", &cas);
while(cas--)
{
scanf("%d%d%d", &n, &m, &p);
init(n, n*m);
for(int i = ; i <= p; i++)
{
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
H[i] = -;
for(int j = x1; j < x2; j++)
for(int k = y1; k < y2; k++)
ins(i, j*m+k+);
}
ans = oo;
dfs();
printf("%d\n", ans == oo ? - : ans);
}
return ;
}
POJ 3074 Sudoku
用Dancing Link是解决数独问题的利器。具体也可以参考博文开头给出的资料链接。
看完那篇文章后,我就在想:Dancing Link解数独问题中,为什么要另外用81列来限制数独是否已经填满?:在行列宫的唯一性被完全覆盖的情况下(81*3列)已经说明数独已经填满了吗?想了好久才想明白,其实这个问题非常简单,如果不用81列来限制,数独每个位置只填一个数,那么会出现即使行列宫唯一性都满足的前提下有些格子被两个数覆盖,从反面想,如果没有了81列来限制数独是否填满,那么我们构造出的列为:
行1填1 行1填2 行1填3 ... 列1填1 列1填2 列1填3 ... 宫1有1 宫1有2 宫1有3 ...
那么,可以有(1,1,1)和(1,1,2)同时合法并覆盖“行1填1,行1填2,列1填1,列1填2”,但显然,这是不合法的,因为一个格子只能填一个数!终于想通了啊。
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int A = ;
const int N = A*A*A+;
const int M = (A+A+A)*A+A*A+;
const int head = ;
const int oo = 0x3f3f3f3f; int U[N*M], D[N*M], L[N*M], R[N*M];
int S[N*M], O[N*M], H[N*M];
int X[N*M], Y[N*M];
int n, num, sz, len, p;
bool g[N][M];
char s[];
int ans[N][M]; void init(int m)
{
for(int i = ; i <= m; i++)
{
U[i] = D[i] = i;
L[i+] = i;
R[i] = i+;
S[i] = ;
}
R[m] = ;
L[] = m;
sz = m+;
} void ins(int r, int c)
{
S[c]++;
D[U[c]] = sz;
U[sz] = U[c];
D[sz] = c;
U[c] = sz;
X[sz] = c;
Y[sz] = r;
if(H[r] == -)
H[r] = L[sz] = R[sz] = sz;
else
{
R[L[H[r]]] = sz;
L[sz] = L[H[r]];
R[sz] = H[r];
L[H[r]] = sz;
}
sz++;
} void remove(const 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[X[j]];
}
}
} void resume(const int &c)
{
for(int i = D[c]; i != c; i = D[i])
{
for(int j = R[i]; j != i; j = R[j])
{
++S[X[j]];
U[D[j]] = j;
D[U[j]] = j;
}
}
L[R[c]] = c;
R[L[c]] = c;
} bool dfs(const int &k)
{
if(R[head] == head)
return true; int s(oo), c;
for(int t = R[head]; t != head; t = R[t])
{
if(S[t] < s)
{
s = S[t];
c = t;
}
}
remove(c);
for(int i = D[c]; i != c; i = D[i])
{
ans[Y[i]/][Y[i]%/] = Y[i]%+;
for(int j = R[i]; j != i; j = R[j])
remove(X[j]);
if(dfs(k+))
return true;
for(int j = L[i]; j != i; j = L[j])
resume(X[j]);
}
resume(c);
return false;
} void love(int i, int j, int k)
{
int row = (i*+j)*+k;
g[row][i*+j] = true;
g[row][*+i*+k] = true;
g[row][*+j*+k] = true;
int a = i/, b = j/;
g[row][* + (a*+b)*+k] = true;
} int main()
{
while(scanf("%s", s) != EOF)
{
if(strcmp(s, "end") == ) break;
init(A*A*);
memset(g, false, sizeof g);
memset(H, -, sizeof H);
for(int i = ; i < A; i++)
{
for(int j = ; j < A; j++)
{
if(s[i*A+j] != '.')
{
int k = s[i*A+j]-'';
love(i, j, k);
}
else
{
for(int k = ; k < A; k++)
love(i, j, k);
}
}
}
for(int i = ; i < N; i++)
for(int j = ; j < M; j++)
if(g[i][j])
ins(i, j+); // column id begin from 1, not 0, so j plus 1 dfs();
for(int i = ; i < ; i++)
for(int j = ; j < ; j++)
printf("%d", ans[i][j]);
putchar('\n');
}
return ;
}
POJ 3076 Sudoku
和POJ3074一样,只不过是16*16的数独。
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int A = ;
const int N = A*A*A+;
const int M = A*A*+;
const int head = ;
const int oo = 0x3f3f3f3f; int U[N*M], D[N*M], L[N*M], R[N*M];
int S[N*M], O[N*M], H[N*M];
int X[N*M], Y[N*M];
int n, num, sz, len, p;
bool g[N][M];
char s[][];
int ans[N][M]; void init(int m)
{
for(int i = ; i <= m; i++)
{
U[i] = D[i] = i;
L[i+] = i;
R[i] = i+;
S[i] = ;
}
R[m] = ;
L[] = m;
sz = m+;
} void ins(int r, int c)
{
S[c]++;
D[U[c]] = sz;
U[sz] = U[c];
D[sz] = c;
U[c] = sz;
X[sz] = c;
Y[sz] = r;
if(H[r] == -)
H[r] = L[sz] = R[sz] = sz;
else
{
R[L[H[r]]] = sz;
L[sz] = L[H[r]];
R[sz] = H[r];
L[H[r]] = sz;
}
sz++;
} void remove(const 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[X[j]];
}
}
} void resume(const int &c)
{
for(int i = D[c]; i != c; i = D[i])
{
for(int j = R[i]; j != i; j = R[j])
{
++S[X[j]];
U[D[j]] = j;
D[U[j]] = j;
}
}
L[R[c]] = c;
R[L[c]] = c;
} bool dfs(const int &k)
{
if(R[head] == head)
return true; int s(oo), c;
for(int t = R[head]; t != head; t = R[t])
{
if(S[t] < s)
{
s = S[t];
c = t;
}
}
remove(c);
for(int i = D[c]; i != c; i = D[i])
{
ans[Y[i]/(A*A)][Y[i]%(A*A)/A] = Y[i]%A;
for(int j = R[i]; j != i; j = R[j])
remove(X[j]);
if(dfs(k+))
return true;
for(int j = L[i]; j != i; j = L[j])
resume(X[j]);
}
resume(c);
return false;
} void love(int i, int j, int k)
{
int row = (i*A+j)*A+k;
g[row][i*A+j] = true;
g[row][A*A*+i*A+k] = true;
g[row][A*A*+j*A+k] = true;
int a = i/, b = j/;
g[row][A*A* + (a*+b)*A+k] = true;
} int main()
{
bool flag = false;
while(scanf("%s", s[]) != EOF)
{
for(int i = ; i < A; i++)
scanf("%s", s[i]);
if(flag) putchar('\n');
flag = true;
init(A*A*);
memset(g, false, sizeof g);
memset(H, -, sizeof H);
for(int i = ; i < A; i++)
{
for(int j = ; j < A; j++)
{
if(s[i][j] != '-')
{
int k = s[i][j] -'A';
love(i, j, k);
}
else
{
for(int k = ; k < A; k++)
love(i, j, k);
}
}
}
for(int i = ; i < N; i++)
for(int j = ; j < M; j++)
if(g[i][j])
ins(i, j+); dfs();
for(int i = ; i < A; i++)
{
for(int j = ; j < A; j++)
putchar(ans[i][j]+'A');
putchar('\n');
}
}
return ;
}
POJ2676 HDU2780 HDU3111 都是差不多的,不提。
HDU 3909 Sudoku
这道题总的来说是简单的,弄清题意就行。这道题我对DLX解数独更进一步了解了,在dfs函数中,要想得到一个解,那么必须在找到一个解的时候return true,如果不设返回值,那么得到的解会被后面的继续深搜覆盖掉,所以要及时返回。如果想知道是否有多个解,那么,可以新建变量cnt进行计数。
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
#define pii pair<int,int>
#define clr(a) memset((a),0,sizeof (a))
#define rep(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(a);i>=(int)(b);i--)
#define oo 0x3f3f3f3f
#define eps 1e-6
#define N (16*16*16+5)
#define M (16*16*4+5)
#define mod 1000000007
#define MP make_pair
#define PB push_back
#define RI(x) scanf("%d",&x)
#define RII(x,y) scanf("%d%d",&x,&y)
#define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z)
typedef long long LL; const int head = ; int A;
int U[N*M], D[N*M], L[N*M], R[N*M];
int S[N*M], O[N*M], H[N*M];
int X[N*M], Y[N*M];
int n, num, sz, len, p;
bool g[N][M];
char s[][];
int ans[][], b[][], cnt; void init(int m)
{
for(int i = ; i <= m; i++)
{
U[i] = D[i] = i;
L[i+] = i;
R[i] = i+;
S[i] = ;
}
R[m] = ;
L[] = m;
sz = m+;
} void ins(int r, int c)
{
S[c]++;
D[U[c]] = sz;
U[sz] = U[c];
D[sz] = c;
U[c] = sz;
X[sz] = c;
Y[sz] = r;
if(H[r] == -)
H[r] = L[sz] = R[sz] = sz;
else
{
R[L[H[r]]] = sz;
L[sz] = L[H[r]];
R[sz] = H[r];
L[H[r]] = sz;
}
sz++;
} void remove(const 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[X[j]];
}
}
} void resume(const int &c)
{
for(int i = D[c]; i != c; i = D[i])
{
for(int j = R[i]; j != i; j = R[j])
{
++S[X[j]];
U[D[j]] = j;
D[U[j]] = j;
}
}
L[R[c]] = c;
R[L[c]] = c;
} bool dfs(const int &k, bool f)
{
if(R[head] == head)
{
if(cnt || f)
{
cnt++;
return true;
}
cnt++;
return false;
}
int s(oo), c;
for(int t = R[head]; t != head; t = R[t])
{
if(S[t] < s)
{
s = S[t];
c = t;
}
}
remove(c);
for(int i = D[c]; i != c; i = D[i])
{
ans[Y[i]/(A*A)][Y[i]%(A*A)/A] = Y[i]%A+;
for(int j = R[i]; j != i; j = R[j])
remove(X[j]);
if(dfs(k+, f)) return true;
for(int j = L[i]; j != i; j = L[j])
resume(X[j]);
}
resume(c);
return false;
} void love(int i, int j, int k)
{
int row = (i*A+j)*A+k;
g[row][i*A+j] = true;
g[row][A*A*+i*A+k] = true;
g[row][A*A*+j*A+k] = true;
int p = (int)sqrt(A);
int a = i/p, b = j/p;
g[row][A*A* + (a*p+b)*A+k] = true;
} void solve()
{
cnt = ;
init(A*A*);
memset(g, false, sizeof g);
memset(H, -, sizeof H);
for(int i = ; i < A; i++)
{
for(int j = ; j < A; j++)
{
if(s[i][j] != '.')
{
int k;
if(s[i][j] >= '' && s[i][j] <= '') k = s[i][j] - '';
else k = s[i][j] - 'A' + ;
love(i, j, k);
}
else
{
for(int k = ; k < A; k++)
love(i, j, k);
}
}
}
for(int i = ; i < N; i++)
{
for(int j = ; j < M; j++)
{
if(g[i][j])
ins(i, j+);
}
}
} int main()
{
while(RI(A) != EOF)
{
A = A * A;
rep(i,,A-)
scanf("%s", s[i]);
solve();
dfs(, );
if(cnt == )
{
puts("No Solution");
continue;
}
else if(cnt > )
{
puts("Multiple Solutions");
continue;
}
for(int i = ; i < A; i++)
{
for(int j = ; j < A; j++)
{
if(s[i][j] != '.')
{
char c = s[i][j];
s[i][j] = '.';
solve();
dfs(, );
if(cnt < )
goto end ;
s[i][j] = c;
}
}
}
solve();
dfs(, );
for(int i = ; i < A; i++)
{
for(int j = ; j < A; j++)
{
if(ans[i][j] <= )
printf("%d", ans[i][j]);
else
printf("%c", ans[i][j]-+'A');
}
putchar('\n');
}
continue;
end:
puts("Not Minimal");
}
return ;
}
HDU 3663 Power Stations
很不错的一道题。
首先,对于列来说,我们需要每个城市在D天里都要有电供应,那么,我们需要D*n列表示每个成绩每一天的状态。对于行,我们需要建立n*25行表示第i个城市作为发电站各个发电时间区间的值,比如,对于区间[1,3],我们拆成[0,0],[1,1],[1,2],[1,3],[2,3],[3,3](拆成25行为了方便计算,实际上有些样例不需要这么多行,空行不影响结果)。但是,现在有一个问题需要面对:一个发电站发电区间只能选一个。为此,新开n行,表示如果某个城市选择了一个区间,就锁定该城市。还要注意重边情况。
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N = ;
const int M = ;
const int oo = 0x3f3f3f3f; int U[N*M], D[N*M], L[N*M], R[N*M];
int S[N*M], O[N*M], H[N*M];
int X[N*M], Y[N*M];
int n, m, d, num, sz, len, p;
int g[N][M]; int hh[][]; struct Node
{
int s, e;
}ans[N]; void init(int m)
{
for(int i = ; i <= m; i++)
{
U[i] = D[i] = i;
L[i+] = i;
R[i] = i+;
S[i] = ;
}
R[m] = ;
L[] = m;
sz = m+;
} void ins(int r, int c)
{
S[c]++;
D[U[c]] = sz;
U[sz] = U[c];
D[sz] = c;
U[c] = sz;
X[sz] = c;
Y[sz] = r;
if(H[r] == -)
H[r] = L[sz] = R[sz] = sz;
else
{
R[L[H[r]]] = sz;
L[sz] = L[H[r]];
R[sz] = H[r];
L[H[r]] = sz;
}
sz++;
} void remove(const 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[X[j]];
}
}
} void resume(const int &c)
{
for(int i = D[c]; i != c; i = D[i])
{
for(int j = R[i]; j != i; j = R[j])
{
++S[X[j]];
U[D[j]] = j;
D[U[j]] = j;
}
}
L[R[c]] = c;
R[L[c]] = c;
} bool dfs(const int &k)
{
if(R[] == )
{
O[k] = -;
return true;
}
int s(oo), c;
for(int t = R[]; t != ; t = R[t])
{
if(S[t] < s)
{
s = S[t];
c = t;
}
}
remove(c);
for(int i = D[c]; i != c; i = D[i])
{
O[k] = Y[i];
for(int j = R[i]; j != i; j = R[j])
remove(X[j]);
if(dfs(k+))
return true;
for(int j = L[i]; j != i; j = L[j])
resume(X[j]);
}
resume(c);
return false;
} int main()
{
int a, b;
while(scanf("%d%d%d", &n, &m, &d) != EOF)
{
memset(hh, , sizeof hh);
memset(g, , sizeof g);
memset(H, -, sizeof H);
for(int i = ; i < m; i++)
{
scanf("%d%d", &a, &b);
hh[a][b] = hh[b][a] = ;
}
init(d*n+n);
for(int i = ; i < n; i++)
{
scanf("%d%d", &a, &b);
for(int j = a-; j < b; j++)
{
for(int k = j; k < b; k++)
{
for(int u = j; u <= k; u++)
{
g[i*+j*+k][u*n+i+] = ;
g[i*+j*+k][d*n+i+] = ;
for(int v = ; v <= n; v++)
if(hh[i+][v])
g[i*+j*+k][u*n+v] = ;
}
}
}
}
for(int i = ; i < n; i++) // 每个城市的[0,0]区间
g[*n+i][d*n+i+] = ;
for(int i = ; i < n*+n; i++)
for(int j = ; j <= d*n+n; j++)
if(g[i][j]) ins(i, j); if(!dfs())
puts("No solution\n");
else
{
memset(ans, , sizeof ans);
for(int i = ; O[i] != -; i++)
{
if(O[i] >= *n) continue;
ans[O[i]/+].s = O[i]%/+;
ans[O[i]/+].e = O[i]%+;
}
for(int i = ; i <= n; i++)
printf("%d %d\n", ans[i].s, ans[i].e);
putchar('\n');
}
}
return ;
}
【Dancing Link专题】解题报告的更多相关文章
- Dancing Link专题
一些链接: http://www.cnblogs.com/-sunshine/p/3358922.html http://www.cnblogs.com/grenet/p/3145800.html 1 ...
- 2014 UESTC暑前集训动态规划专题解题报告
A.爱管闲事 http://www.cnblogs.com/whatbeg/p/3762733.html B.轻音乐同好会 C.温泉旅馆 http://www.cnblogs.com/whatbeg/ ...
- 2014 UESTC暑前集训数据结构专题解题报告
A.Islands 这种联通块的问题一看就知道是并查集的思想. 做法:从高水位到低水位依序进行操作,这样每次都有新的块浮出水面,可以在前面的基础上进行合并集合的操作.给每个位置分配一个数字,方便合并集 ...
- 2014 UESTC暑前集训搜索专题解题报告
A.解救小Q BFS.每次到达一个状态时看是否是在传送阵的一点上,是则传送到另一点即可. 代码: #include <iostream> #include <cstdio> # ...
- 2014 UESTC暑前集训图论专题解题报告
A.方老师和缘分 http://www.cnblogs.com/whatbeg/p/3765621.html B.方老师和农场 http://www.cnblogs.com/whatbeg/p/376 ...
- NOIP2009解题报告
09年的题总体来说 没有难题,但是每道题除了第一题都要认真的慢慢写才能AC, 第一题: R国和S国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动. 历经艰险后,潜伏于S国的R国间谍小C终于摸清 ...
- POJ 3126 Prime Path 解题报告(BFS & 双向BFS)
题目大意:给定一个4位素数,一个目标4位素数.每次变换一位,保证变换后依然是素数,求变换到目标素数的最小步数. 解题报告:直接用最短路. 枚举1000-10000所有素数,如果素数A交换一位可以得到素 ...
- hdu1853解题报告
题意和解决回路匹配的思路如同hdu3488 (这里我第一次想到最短路,但是对于有回路这个不知道怎么处理,后来看了别人的解题报告才知道KM匹配,但是看到KM之后就自己想...想了很久....还是不知道回 ...
- [置顶] 刘汝佳《训练指南》动态规划::Beginner (25题)解题报告汇总
本文出自 http://blog.csdn.net/shuangde800 刘汝佳<算法竞赛入门经典-训练指南>的动态规划部分的习题Beginner 打开 这个专题一共有25题,刷完 ...
随机推荐
- jquery用ajax方式从后台获取json数据,将内容填充到下拉列表。
从后台获取json数据,将内容填充到下拉列表. url:链接 par:ID sel:下拉列表选择器 //获取下拉列表 function BuildSelectBox(url, par, sel) { ...
- [leetcode]_Add Two Numbers
题目:两个链表存储数字,然后求和,和值存储在一个链表中. 代码: public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode ...
- luigi学习3-使用luigid
--local-scheduler的方式只适用于开发调试阶段,当你真正要把程序部署到一个产品时,我们推荐使用luigid服务. 使用luigid服务不但能提供锁服务(防止一个任务被多个进程重复执行), ...
- php输出utf-8格式
header("Content-type:text/html;charset=utf-8"); 输出数据前插入以上代码,以utf-8格式输出,避免乱码
- 全排列 (codevs 1294)题解
[题目描述] 给出一个n, 请输出n的所有全排列(按字典序输出). [样例输入] 3 [样例输出] 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 [解题思路] 听说C++有作 ...
- .Net并行编程
1.什么是线程?线程和进程的区别是什么? 线程是程序执行的最小单元. 区别: 进程是操作系统进行资源处理和分配的最小单位,而一个进程可以包含多个线程,并共享进程的资源. 2.什么是多线程?为什么设计多 ...
- selenium+python登录登出百度,等待页面加载,鼠标定位
#coding:gbk from selenium import webdriver from selenium.webdriver.common.keys import Keys from sele ...
- 安装使用rspec
一,安装ruby. 二,运行命令,安装rspec的gem包: gem install rspec 会看到如下的结果: Fetching: rspec-core-2.14.7.gem (100%) Fe ...
- EF - 批量插入
比较一下下面两种方式的区别 1,每Add一次 就savechange() static void Main(string[] args) { //List<User> users= Fin ...
- Resizing the View(待续。。。。)
在iOS开发的过程中,控件的大小和位置如何去安排是一个现在看来比较麻烦的事情,需要从上到下的通知和从下到上的调整.而这部分在整个开发过程中是比较重要的,但是却经常没有被掌握.如果将这部分掌握,不管界面 ...