您的位置:首页 > 其它

Uva 307木棍、387谜题、10160服务站总结

2014-04-23 13:47 316 查看
本文所讨论的几个问题均为NP完全问题,所以自然解决的办法就是智能穷举,设计算法时为穷举选择合适的剪枝是在短时间内解决问题的最佳选择。

1.木棍问题

#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
#define maxn 65
int 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<cstdio>
#include<cstring>
#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;
else
putchar('\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');
}
} else
puts("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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: