hdu 3663 (dancing links)精确覆盖
来源:互联网 发布:照相馆制作照片软件 编辑:程序博客网 时间:2024/06/02 14:52
题目描述:
有n个城市,还有m条边(双向),每个城市都有一个发电站,如果一个发电站工作,它能够给它所在的城市和直接相邻的城市提供电力。并且要求每个城市只能由一个发电站来提供电力(即不能够被两个或以上的发电站同时覆盖)。
然后,每个城市的发电站都有一个允许工作时间 ai bj,表示发电站只能在[ai,bi]内的某个连续区间内工作(也可以一个都不选),并且只能选一个区间(即ai = 1, bi = 5, 不能选择1-2 和4-5两个区间)。
然后给你一个数字D,问你能不能安排这n个发电站的工作时间使1~D的时间区间内,每个城市在每个时间都能够被一个发电站覆盖。
可以的话输出任意一种解决方法。
n <= 60, m<= 150, D<=5
解题报告:
初看题意,是一个覆盖问题,n又很小,搜,怎么搜,DLX的精确覆盖模型。
精确覆盖:一个0,1矩阵,选择某些行,使每一列都有且仅有一个1。即用行覆盖列。
行的定义:
一共n * 16行,16就是[1,5]区间的所有小区间:
{{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5},
{2, 2}, {2, 3}, {2, 4}, {2, 5},
{3, 3}, {3, 4}, {3, 5},
{4, 4}, {4, 5},
{5, 5}, {0, 0}};
其中0,0表示不用。
这样第(i – 1) * 16 + j就表示第i个发电站选择小区间j时状态。
(1 <= i <= n, 1 <= j <= 16)
列的定义:
对于第(a – 1) * 16 + b行,一共有n * d + n列。
第(i – 1) * d + j列表示第i个城市的第j天 是否被这一行的状态(a发电站选择b区间)供电,
第n * d + j列为1表示这个覆盖来自第j个发电站(因为每个发电站只能用一次,所以要用额外的n列来限制,和数独那题的解法类似,由于这n列每一列只能被覆盖一次,就限制了使用次数也是1)。
这样图就建好了,套用DLX模板即可。有界的话就输出一个就好了。
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <algorithm> #include <vector> #include <bitset> #include <queue> #define ll long long using namespace std; const int maxn = 60 * 20; const int maxm = 60 * 10; const int max_size = maxn * maxm; const int INF = 1e9; int L[max_size], R[max_size], U[max_size], D[max_size], C[max_size], H[max_size]; int S[max_size], O[max_size],row[max_size]; int head, size; int n, m, d, len; vector<int> G[100]; int st[100], ed[100], ans[100]; bool mat[maxn][maxm]; int move[16][2] = {{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 2}, {2, 3}, {2, 4}, {2, 5}, {3, 3}, {3, 4}, {3, 5}, {4, 4}, {4, 5}, {5, 5}, {0, 0}}; void init(int N,int M){ int i; for (i = 1; i <= N; i++) H[i] = -1; for (i = 0; i <= M; i++) { S[i] = 0; L[i + 1] = i; R[i] = i + 1; U[i] = D[i] = i; } R[M] = 0; size = M + 1; } void Link(int r,int c){ U[size] = c; D[size] = D[c]; U[D[c]] = size; D[c] = size; if (H[r] < 0) H[r] = L[size] = R[size] = size; else { L[size] = H[r]; R[size] = R[H[r]]; L[R[H[r]]] = size; R[H[r]] = size; } S[c]++; row[size] = r ; C[size++] = c; }void Remove(int c) { //删除c列及相应的行 int i, j; R[L[c]] = R[c]; L[R[c]] = L[c]; for (i = D[c]; i != c; i = D[i]) { for (j = R[i]; j != i; j = R[j]) { U[D[j]] = U[j]; D[U[j]] = D[j]; S[C[j]]--; } } } void Resume(int c) { //恢复c列 int i, j; R[L[c]] = c; L[R[c]] = c; for (i = D[c]; i != c; i = D[i]) { for (j = R[i]; j != i; j = R[j]) { U[D[j]] = j; D[U[j]] = j; S[C[j]]++; } } } bool Dance(int now) { //舞蹈链 if (R[0] == 0) //输出答案 { len = now; return true; } int i, j, temp, c; for (temp=INF,i = R[0]; i; i = R[i]) { if(S[i]<temp) { temp=S[i]; c=i; } } Remove(c); for(i=D[c];i!=c;i=D[i]) { O[now]=row[i] ; //记录答案 ; for(j=R[i];j!=i;j=R[j]) Remove(C[j]); if(Dance(now+1)) return true; for(j=L[i];j!=i;j=L[j]) Resume(C[j]); } Resume(c); return false; } int main() { int a, b; while(~scanf("%d%d%d", &n, &m, &d)) { for(int i = 1; i <= n; i++) { G[i].clear(); G[i].push_back(i); } for(int i = 0; i < m; i++) { scanf("%d%d", &a, &b); G[a].push_back(b); G[b].push_back(a); } for(int i = 1; i <= n; i++) scanf("%d%d", &st[i], &ed[i]); memset(mat, 0, sizeof(mat)); for(int i = 1; i <= n; i++) { for(int j = 0; j < 15; j++) { int x = (i - 1) * 16 + j + 1; if(move[j][0] >= st[i] && move[j][1] <= ed[i]) { for(int k = 0; k < (int) G[i].size(); k++) { int v = G[i][k]; for(int l = move[j][0]; l <= move[j][1]; l++) mat[x][(v - 1)* d + l] = 1; } mat[x][n * d + i] = 1; } } mat[(i - 1) * 16 + 16][n * d + i] = 1; } int N=n*16,M=n*d+n ; //行数列数 init(N, M); //初始化 //构造十字链表 for (int i = 1; i <= N; ++i) for (int j = 1; j <= M; ++j) { if (!mat[i][j]) continue; else Link(i,j) ; //插入 } Dance(0); //舞蹈链 if(len != n) printf("No solution\n"); else { for(int i = 0; i < len; i++) { int tmp = ((O[i] - 1) / 16) + 1; int tmp2 = O[i] - (tmp - 1) * 16 - 1; ans[tmp] = tmp2; } for(int i = 1; i <= n; i++) printf("%d %d\n", move[ans[i]][0], move[ans[i]][1]); } puts(""); } return 0; }
- hdu 3663 (dancing links)精确覆盖
- hdu 3663 Power Stations(精确覆盖 Dancing Links 模版)
- dancing links精确覆盖模版
- HDU 4069 Squiggly Sudoku【Dancing Links精确覆盖】
- Spoj 1771(Dancing Links 精确覆盖变形)
- 用Dancing Links求解精确覆盖问题
- 精确覆盖问题的dancing links 技术
- Hdu 3663 Dancing Links
- Dancing Links + A* 应用于精确覆盖、重复覆盖
- hdu 3335 Divisibility(Dancing Links重复覆盖)
- HDU 3498 whosyourdaddy【Dancing Links重复覆盖】
- HDU 5046 Airport ( Dancing Links 重复覆盖 )
- hdu 2295 dancing links 求重复覆盖
- zoj 3122(数独 Dancing Links精确覆盖)
- Dancing Links 精确覆盖问题的快速dfs
- poj 3740 Easy Finding(Dancing Links 精确覆盖)
- ZOJ 3209 Treasure Map (Dancing Links 精确覆盖 )
- 【POJ3740】Easy Finding DLX(Dancing Links)精确覆盖问题
- ImageView中显示SD卡上的图片或ImageView图片保存在SD卡上
- NSPredicate
- Maven常用命令
- JAVA学习之JSTL与EL
- 正则表达式小用
- hdu 3663 (dancing links)精确覆盖
- Rotate List
- 数组中n个数出现次数超过1/(1+n),求这些数
- cocosStudio导入cocos2d-3x
- [Warning] TIMESTAMP with implicit DEFAULT value
- atitit.404错误的排查流程总结vOa6
- RSA机密的原理
- Android应用如何适配不同分辨率的手机
- 2014/10/7 闹中修静--静心