uvalive3667 ruler

2 篇文章 0 订阅

tips:

回溯

use a queue to restore the temporary marked array(vis) , and when it back, set vis = 0

first floor give out all the received res, and combine with all the d to make new res, and mark all length which can get then,

code:

<pre name="code" class="cpp">#include<cstdio>
#include<cmath>
#include<string>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 55;
int d[maxn], vis[maxn];
int pos[1000005];
int n, len;
int res[maxn];

bool dfs(int cnt) {
	if(cnt == len) {
		for(int i=1; i<n; i++) {
			if(!vis[i]) return false;
		}
		return true;
	}
	queue<int> q;
	for(int i=1; i<cnt; i++)  {
		for(int j=1; j<n; j++) {
			if(!vis[j]) {
				int temp = res[i]+d[j];
				if(temp <= res[cnt-1] || temp >= d[n])continue;
				//make sure that the new answer is biger than ever
				res[cnt] = temp;
				for(int k=1; k<cnt; k++) {
					temp = res[cnt]-res[k];
					if(vis[pos[temp]]==0 && pos[temp]) {
						q.push(pos[temp]);
						vis[pos[temp]] = 1;
					}
				}
				temp = d[n]-res[cnt];
				if(!vis[pos[temp]] && pos[temp]) {
					vis[pos[temp]] = 1;
					q.push(pos[temp]);
				}
				if(dfs(cnt+1)) return true;
				while(!q.empty()) {
					vis[q.front()]=0;
					q.pop();
				}

			}
		}
	}
	return false;
}

int main() {
	int kase=1;
	while(scanf("%d", &n) != EOF && n) {
		memset(vis, 0 ,sizeof(vis));
		memset(pos, 0, sizeof(pos));
		for(int i=1; i<=n; i++)
			scanf("%d", &d[i]);
        sort(d + 1, d + 1 + n);  
        n = unique(d + 1, d + 1 + n) - d - 1;  
        for (int i = 1; i <= n; i++)  
            pos[d[i]] = i;  
        len = sqrt(2 * n) - 1;  
        res[1] = 0;  
        while (!dfs(2))  
            len++;  
        res[len] = d[n];  
        printf("Case %d:\n", kase++);  
        printf("%d\n", len);  
        for (int i = 1; i <= len; i++)  
            printf("%d ", res[i]);  
        printf("\n"); 
	}
	return 0;
}
		

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值