Uva 307木棍、387谜题、10160服务站总结
本文所讨论的几个问题均为NP完全问题,所以自然解决的办法就是智能穷举,设计算法时为穷举选择合适的剪枝是在短时间内解决问题的最佳选择。
1.木棍问题
#include
#include
#include using namespace std;#define maxn 65int n, sum, goal;int stick[maxn];bool visit[maxn];bool cmp(const int &a, const int &b) {return a > b;}bool dfs(int now, int index, int cnt) {if(goal * cnt == sum) return true;//所有木棍拼凑成功if(stick[n-1]>goal-now)return false;//当前所剩的最短木棍的长度都大于现阶段拼凑原木棍剩下的长度,无需继续递归for(int i = index; i < n; i++) {//由于对木棍按长度排序了,所以i的初值是index而不是0,我们才选择小木棍时,无需考虑大木棍,排序确保了大木棍在之前处理了。if(visit[i] || (i && !visit[i-1] && stick[i] == stick[i-1])) continue;//两个木棍长度一样,那么使用前一个无法成功,自然使用这个也无法成功。if(now + stick[i] == goal) {visit[i] = true;if(dfs(0, 0, cnt + 1)) return true;visit[i] = false;
//若使用此木棍最后拼成了当前原木棍,但是,后面的原木棍无法拼凑成功,则无需继续递归。
//举例说明:若此木块长为x,你可以从后面选取总长为x的木块若干,再次拼凑出该原木棍。但是,依然无法利用此木棍长度为x拼凑成功后面的原木棍。return false;} else if(now + stick[i] < goal) {visit[i] = true;if(dfs(now + stick[i], i + 1, cnt)) return true;visit[i] = false;if(now == 0) return false;//对于拼凑当前“全新”的原木棍,若使用木棍无法拼凑成功,后面任一“全新”原木棍都不能含它,题意要求使用所有木棍,无需继续递归。}}return false;}int solve() {sort(stick, stick + n, cmp);for(goal = stick[0]; goal < sum; goal++) {if(sum % goal != 0) continue;memset(visit, false, sizeof(visit));if(dfs(0, 0, 0)) break;}return goal;}int main() {while(~scanf("%d", &n)) {if(!n) break;sum = 0;for(int i = 0; i < n; i++) {scanf("%d", &stick[i]);sum += stick[i];}printf("%d\n", solve());}return 0;}
以上就是解决这个问题的源代码,uva:runtime 0.193s ranking 46
2.387谜题
对于这个问题,请参考精确覆盖问题,利用Dancing Link优化。
#include
#include
#define MAXM 10
#define MAXN 100000
#define MAXL 110
#define INF 0x7FFFFFFF
struct node {int h, l;char s[MAXM][MAXM];
};
struct answer {int pos, h, l;
};
answer ans[MAXL];
node sq[MAXM];
bool vis[MAXL];
int L[MAXN], R[MAXN], U[MAXN], D[MAXN];//上下左右
int H[MAXN], S[MAXN], C[MAXN], X[MAXN];
int size;
char a[MAXM][MAXM];
void Init(int m) {int i;memset(vis, false, sizeof(vis));for (i = 0; i <= m; i++) {L[i + 1] = i;R[i] = i + 1;U[i] = D[i] = i;S[i] = 0;}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]++;X[size] = r;C[size++] = c;
}
void Remove(int c) {//缩减双向十字链表int i, j;L[R[c]] = L[c];R[L[c]] = R[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) {//恢复双向十字链表int i, j;L[R[c]] = R[L[c]] = c;for (i = D[c]; i != c; i = D[i]) {for (j = R[i]; j != i; j = R[j]) {U[D[j]] = D[U[j]] = j;S[C[j]]++;}}
}
bool Dance() {if (R[0] == 0)return true;int i, j, temp, c;for (temp = INF,i = R[0]; i; i = R[i]) {if (temp > S[i]) {temp = S[i];c = i;}}Remove(c);for (i = D[c]; i != c; i = D[i]) {vis[X[i]] = true;for (j = R[i]; j != i; j = R[j])Remove(C[j]);if (Dance())return true;for (j = L[i]; j != i; j = L[j])Resume(C[j]);vis[X[i]] = false;}Resume(c);return false;
}
void Build(int n) {int i, j, k, t, p, r;for (i = r = 0; i < n; i++) {for (j = 0; j <= 4 - sq[i].h; j++) {for (k = 0; k <= 4 - sq[i].l; k++) {H[++r] = -1;Link(r, 16 + i + 1);ans[r].pos = i;ans[r].h = j;ans[r].l = k;for (t = 0; t < sq[i].h; t++) {for (p = 0; p < sq[i].l; p++) {if (sq[i].s[t][p] != '0')Link(r, 4 * (j + t) + k + p + 1);}}}}}
}
int main() {//freopen("C:\\Users\\Ron\\Desktop\\sample.txt","r",stdin);int n, i, j, k;bool flag = true;while (scanf("%d", &n), n) {if (flag)flag = false;elseputchar('\n');Init(16 + n);for (i = 0; i < n; i++) {scanf("%d%d", &sq[i].h, &sq[i].l);for (j = 0; j < sq[i].h; j++) {for (k = 0; k < sq[i].l; k++)scanf(" %c", &sq[i].s[j][k]);}}Build(n);if (Dance()) {for (i = 1; i < MAXL; i++) {if (vis[i]) {for (j = 0; j < sq[ans[i].pos].h; j++) {for (k = 0; k < sq[ans[i].pos].l; k++) {if (sq[ans[i].pos].s[j][k] != '0')a[j + ans[i].h][k + ans[i].l] = '1'+ ans[i].pos;}}}}for (i = 0; i < 4; i++) {for (j = 0; j < 4; j++)putchar(a[i][j]);putchar('\n');}} elseputs("No solution possible");}while(true);return 0;
} 此为387谜题问题,dancing link源代码,因为我自己看的也是云山雾绕也没加注释。 Uva:runtime 0.089s ranking 67。有兴趣的朋友可以深入研究精确覆盖问题。
本人没有使用此法,就是利用简单的穷举加回溯得到了Uva AC。不过时间多了很多2.2s。
3.服务站
请参考寂静山林博客 ,想尽各种办法,如果不对地图进行拆分,基本上都是TLE。本来想要转载此文,并进行进一步说明,心想也没有太大必要,原文也很不错。
博客里有源码:Uva: runtime 0.029s ranking 70。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
