博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
UVA 10123 No Tipping
阅读量:5079 次
发布时间:2019-06-12

本文共 4857 字,大约阅读时间需要 16 分钟。

UVA_10123

    以下斜体部分是我第一次写的解题报告,但后来越来越觉得我实现的程序和我的想法并不怎么挂钩,于是就越发怀疑程序里那个剪枝的正确性了。

    再后来看了UVA的论坛之后,发现上面有人提到用记忆化搜索去解,我这时再一看N只有20,完全可以用状态压缩+记忆化搜索来做,只是当时没有想到,其中一部分原因也是觉得LRJ放在了回溯这章里面,就压根没向着dp的方向去考虑,一直在想怎么剪枝去了,便也凑巧,居然诞生了下面的我现在也不知道正确与否的回溯做法。以后千万不要局限于已知的这题的归类,换个思路也许就能海阔天空了。

    如果各位兄台谁有兴趣证明出了或者推翻了下面这个回溯的程序,还望能和小弟分享一下。当然,这个回溯程序在UVA上是能AC的,而且跑得很快,但我后来总觉得这个程序的剪枝有问题。

    下面还是说一下dp的思路吧。由于N不大,2的20次方也就10^6左右,因此可以把所有木块的状态用2进制表示出来,于是可以用f[i]表示是否可以达到木块的状态为i的这种状态。接下来我们既可以一个一个地向上放,也可以一个一个地向下拿,只要看最后起始状态的f[st]是否为1即可。

    “首先,我们如果考虑怎么拿的话会比较麻烦,不如我们反过来考虑怎么放,如果每个时刻放的都能平衡,那么最后就能得出一个可行解。

    “但是如果直接回溯的话会超时,我们不妨慢慢来优化算法。

    “第一,最好把坐标先乘2化成整数,这样就避免了浮点数误差。

    “第二,我们在放的时候,一个贪心思路就是先把两个支点中间的木块放上,比较容易证明这样只会增加后续木板的稳定程度。

    “第三,我们应该把其余的木块按力矩大小降序排序,支点是离它最近的那个支点,先选力矩小的,这样一定程度上减少了木板弄翻的可能。

    “第四,上面的按力矩排序还带来了额外的好处,我们不妨用两个数组分别存左边和右边的待放的木块。我们先考虑右边的,假设我们现在放了一个木块上去,结果发现后面无论怎么放木板都会右翻,显然就不用再尝试这个木块右边的木块了,因为必然也会右翻。同样,对于左边的木块,假设我们现在放了一个木块上去,结果发现后面无论怎么放木板都会左翻,显然就不用再尝试这个木块左边的木块了,因为必然也会左翻。当然,如果后续可能左翻也可能右翻的话就要继续尝试剩余的木块。

    “考虑完上面几点之后就可以AC了。”

//深搜剪枝,回溯 #include
#include
#include
#define MAXD 30 int L, N, W, s[MAXD], r1[MAXD], r2[MAXD], N1, N2, x[MAXD], w[MAXD], vis[MAXD]; int cmp(const void *_p, const void *_q) {
int *p = (int *)_p; int *q = (int *)_q; int x1 , x2; if(x[*p] < 0) x1 = (-3 - x[*p]) * w[*p]; else x1 = (x[*p] - 3) * w[*p]; if(x[*q] < 0) x2 = (-3 - x[*q]) * w[*q]; else x2 = (x[*q] - 3) * w[*q]; return x1 - x2; } void init() {
int i; for(i = 0; i < N; i ++) {
scanf("%d%d", &x[i], &w[i]); x[i] *= 2; } } int dfs(int left, int right, int num) {
int i, j, k, t, flag, mleft, mright, tleft = 1, tright = 1; if(num == N) return 2; for(i = 0; i < N1; i ++) {
k = r1[i]; if(!vis[k]) {
vis[k] = 1; mleft = left + (x[k] + 3) * w[k], mright = right + (3 - x[k]) * w[k]; s[num] = k; if(mleft >= 0) tleft = 0; if(mleft >= 0 && mright >= 0) {
flag = dfs(mleft, mright, num + 1); if(flag == 2) return 2; if(flag == -1) break; tleft = 0; } vis[k] = 0; } } for(i = 0; i < N2; i ++) {
k = r2[i]; if(!vis[k]) {
vis[k] = 1; mleft = left + (x[k] + 3) * w[k], mright = right + (3 - x[k]) * w[k]; s[num] = k; if(mright >= 0) tright = 0; if(mleft >= 0 && mright >= 0) {
flag = dfs(mleft, mright, num + 1); if(flag == 2) return 2; if(flag == 1) break; tright = 0; } vis[k] = 0; } } return tright - tleft; } void solve() {
int i, j, k, left, right, num; memset(vis, 0, sizeof(vis)); num = 0; left = right = 3 * W; for(i = 0; i < N; i ++) if(x[i] >= -3 && x[i] <= 3) {
s[num ++] = i; vis[i] = 1; left = left + (x[i] + 3) * w[i], right = right + (3 - x[i]) * w[i]; } N1 = N2 = 0; for(i = 0; i < N; i ++) if(!vis[i]) {
if(x[i] < 0) r1[N1 ++] = i; else r2[N2 ++] = i; } qsort(r1, N1, sizeof(r1[0]), cmp); qsort(r2, N2, sizeof(r2[0]), cmp); if(dfs(left, right, num) != 2) printf("Impossible\n"); else {
for(i = N - 1; i >= 0; i --) printf("%d %d\n", x[s[i]] / 2, w[s[i]]); } } int main() {
int t = 0; for(;;) {
scanf("%d%d%d", &L, &W, &N); if(!L) break; init(); printf("Case %d:\n", ++ t); solve(); } return 0; }

 

//状态压缩+记忆化搜索 #include
#include
#define MAXD 1100000 #define MAXN 25 int N, L, W, x[MAXN], w[MAXN]; int f[MAXD], left[MAXD], right[MAXD]; void init() {
int i; for(i = 0; i < N; i ++) {
scanf("%d%d", &x[i], &w[i]); x[i] *= 2; } } int dp(int st) {
int i, k, mleft, mright; if(f[st] != -1) return f[st]; if(st == 0) return f[st] = 1; for(i = 0; i < N; i ++) if((1 << i) & st) {
mleft = left[st] + (x[i] + 3) * w[i]; mright = right[st] + (3 - x[i]) * w[i]; if(mleft >= 0 && mright >= 0) {
k = st ^ (1 << i); left[k] = mleft, right[k] = mright; if(dp(k)) {
printf("%d %d\n", x[i] / 2, w[i]); return f[st] = 1; } } } return f[st] = 0; } void solve() {
int i, st; memset(f, -1, sizeof(f)); st = (1 << N) - 1; left[st] = W * 3, right[st] = W * 3; if(!dp(st)) printf("Impossible\n"); } int main() {
int t = 0; for(;;) {
scanf("%d%d%d", &L, &W, &N); if(!L) break; init(); printf("Case %d:\n", ++ t); solve(); } return 0; }

转载于:https://www.cnblogs.com/staginner/archive/2011/12/21/2295362.html

你可能感兴趣的文章
获取文件编码格式
查看>>
XPO学习(1)----第一个基于XPO的 数据感知应用程序
查看>>
Django-DjangoUeditor
查看>>
MongoDB in Action (MongoDB 实战).pdf
查看>>
Oracle常用SQL与练习
查看>>
spring注解
查看>>
python中random库的使用
查看>>
cheerio 服务器端的jquery
查看>>
心理 情绪
查看>>
vc中debug版本和release版本
查看>>
PCduino+LAMP(Linux Apache Mysql PHP)配置 web server
查看>>
java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).
查看>>
[转载(有删改)]单链表
查看>>
在数组中寻找出现次数大于N/K的数
查看>>
还在门外C++
查看>>
Java开发培训基础知识解析之反射机制
查看>>
位运算处理N皇后
查看>>
C#获取当前页面的url
查看>>
【leetcode】17. Letter Combinations of a Phone Number
查看>>
64位ubuntu 16.04 LTS安装搜狗输入法过程
查看>>