LA 3667 Ruler 两种不同形式的搜索来解决
2015-10-08 21:40
183 查看
这题目让我对bfs有更加深刻的认识了,好题一枚。
解法有两种,一种是递增暴搜,一种是常规的队列搜索
Uva 1377
题意:给定一些要测量的刻度,然后你要制造一把尺子,能测量这些,要求尺子的刻度数尽量少,并且尺子尽量短,题目保证刻度数不会大于7.
递增暴搜通过递增限制条件(刻度位置)
第二种bfs通过将目标也就是状态放入队列的方法来进行搜索。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <queue>
using namespace std;
#define MAX_SIZE 1000010
//#define LOCAL
struct Node
{
set<int> st; //存储当前可表示的刻度
int found; //选取了哪些需要表示的刻度,二进制从小到大表示
};
char idx[MAX_SIZE]; //需要表示那些具体刻度idx[v]即刻度v是否是需要的刻度
set<int> ans;
int N;
int arr[100];
int MAX;//最大刻度
int staus; //满足要求刻度状态
void bfs()
{
Node temp;temp.found=0;temp.st.insert(0);
queue<Node> q;
q.push(temp);
while(!q.empty())
{
Node cur = q.front();q.pop();
if(cur.found==staus)
{
if(cur.st.size()<ans.size())
ans = cur.st;
else if( *cur.st.rbegin() < *ans.rbegin())
ans = cur.st;
return;
}
for(set<int>::iterator iter=cur.st.begin(); iter!=cur.st.end(); iter++) //遍历可表示刻度
{
Node next;int i;
for(i=0; i<N; i++)
{
//如果已被选取
if(cur.found&(1<<i)) continue; //刻度已选取
int v = *iter+arr[i];
if(cur.st.find(v)!=cur.st.end()) continue;//刻度已可表示
if(v>MAX) continue;//超过最大刻度,不需要
next=cur;
next.st.insert(v);
//添加新增此刻度后可表示的新刻度
for(set<int>::iterator iter2=cur.st.begin();iter2!=cur.st.end(); iter2++)
{
int x=abs(v-*iter2);
if(idx[x]!=-1)
{
next.found|=(1<<idx[x]);
}
}
if(next.found!=cur.found)
q.push(next);
}
for(i=0; i<N; i++)
{
//如果已被选取
if(cur.found&(1<<i)) continue; //刻度已选取
int v = *iter-arr[i];
if(cur.st.find(v)!=cur.st.end()) continue;//刻度已可表示
if(v>MAX) continue;//超过最大刻度,不需要
if(v<0) continue;
next=cur;
next.st.insert(v);
//添加新增此刻度后可表示的新刻度
for(set<int>::iterator iter2=cur.st.begin();iter2!=cur.st.end(); iter2++)
{
int x=abs(v-*iter2);
if(idx[x]!=-1)
{
next.found|=(1<<idx[x]);
}
}
if(next.found!=cur.found)
q.push(next);
}
}
}
}
int main()
{
int i,cnt=1;
#ifdef LOCAL
freopen("c:\\1.txt","r",stdin);
#endif
while(scanf("%d",&N)==1)
{
if(N==0) break;
memset(idx,-1,sizeof(idx));
ans.clear();
for(i=0; i<N; i++)
{
scanf("%d",&arr[i]);
ans.insert(arr[i]);
}
sort(arr,arr+N);
N = unique(arr,arr+N) - arr;
MAX=arr[N-1];
for(int i=0; i<N; i++)
idx[arr[i]] = i;
staus = (1<<N)-1;
bfs();
printf("Case %d:\n%d\n",cnt++,ans.size());
for(set<int>::iterator iter=ans.begin(); iter!=ans.end(); ++iter)
printf("%d ",*iter);
printf("\n");
}
return 0;
}
解法有两种,一种是递增暴搜,一种是常规的队列搜索
Uva 1377
题意:给定一些要测量的刻度,然后你要制造一把尺子,能测量这些,要求尺子的刻度数尽量少,并且尺子尽量短,题目保证刻度数不会大于7.
递增暴搜通过递增限制条件(刻度位置)
#include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 55 #define Maxm 1100000 int hav[Maxm],sa[Maxn],n,ans; bool vis[Maxn]; int dis[Maxn]; bool dfs(int cur) { if(cur==ans) { for(int i=1;i<n;i++) //前n-1个长度都能够测量 if(!vis[i]) return false; return true; } for(int i=1;i<cur;i++) { for(int j=1;j<n;j++) { if(!vis[j]) { int dd=dis[i]+sa[j];//当前刻度 if(dd<=dis[cur-1]) //比之前大 continue; if(dd>=sa )//要比最大小 continue; dis[cur]=dd; queue<int>myq; //记录标记的长度,回溯时返回 for(int k=1;k<cur;k++) //加入当前刻度后,新增的能够出的长度 { int temp=dis[cur]-dis[k]; if(hav[temp]&&!vis[hav[temp]]) { vis[hav[temp]]=true; myq.push(hav[temp]); } } int la=sa -dis[cur]; //最后一段 if(hav[la]&&!vis[hav[la]]) { vis[hav[la]]=true; myq.push(hav[la]); } if(dfs(cur+1)) return true; while(!myq.empty()) { la=myq.front(); myq.pop(); vis[la]=false; } } } } return false; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int cas=0; while(~scanf("%d",&n)&&n) { for(int i=1;i<=n;i++) scanf("%d",&sa[i]); sort(sa+1,sa+n+1); n=unique(sa+1,sa+n+1)-sa-1; memset(hav,0,sizeof(hav)); for(int i=1;i<=n;i++) hav[sa[i]]=i; dis[1]=0; ans=2; while(ans*(ans-1)/2<n) ans++; memset(vis,0,sizeof(vis)); while(!dfs(2)) ans++; printf("Case %d:\n%d\n",++cas,ans); printf("%d",dis[1]); dis[ans]=sa ; for(int i=2;i<=ans;i++) printf(" %d",dis[i]); putchar('\n'); } return 0; }
第二种bfs通过将目标也就是状态放入队列的方法来进行搜索。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <queue>
using namespace std;
#define MAX_SIZE 1000010
//#define LOCAL
struct Node
{
set<int> st; //存储当前可表示的刻度
int found; //选取了哪些需要表示的刻度,二进制从小到大表示
};
char idx[MAX_SIZE]; //需要表示那些具体刻度idx[v]即刻度v是否是需要的刻度
set<int> ans;
int N;
int arr[100];
int MAX;//最大刻度
int staus; //满足要求刻度状态
void bfs()
{
Node temp;temp.found=0;temp.st.insert(0);
queue<Node> q;
q.push(temp);
while(!q.empty())
{
Node cur = q.front();q.pop();
if(cur.found==staus)
{
if(cur.st.size()<ans.size())
ans = cur.st;
else if( *cur.st.rbegin() < *ans.rbegin())
ans = cur.st;
return;
}
for(set<int>::iterator iter=cur.st.begin(); iter!=cur.st.end(); iter++) //遍历可表示刻度
{
Node next;int i;
for(i=0; i<N; i++)
{
//如果已被选取
if(cur.found&(1<<i)) continue; //刻度已选取
int v = *iter+arr[i];
if(cur.st.find(v)!=cur.st.end()) continue;//刻度已可表示
if(v>MAX) continue;//超过最大刻度,不需要
next=cur;
next.st.insert(v);
//添加新增此刻度后可表示的新刻度
for(set<int>::iterator iter2=cur.st.begin();iter2!=cur.st.end(); iter2++)
{
int x=abs(v-*iter2);
if(idx[x]!=-1)
{
next.found|=(1<<idx[x]);
}
}
if(next.found!=cur.found)
q.push(next);
}
for(i=0; i<N; i++)
{
//如果已被选取
if(cur.found&(1<<i)) continue; //刻度已选取
int v = *iter-arr[i];
if(cur.st.find(v)!=cur.st.end()) continue;//刻度已可表示
if(v>MAX) continue;//超过最大刻度,不需要
if(v<0) continue;
next=cur;
next.st.insert(v);
//添加新增此刻度后可表示的新刻度
for(set<int>::iterator iter2=cur.st.begin();iter2!=cur.st.end(); iter2++)
{
int x=abs(v-*iter2);
if(idx[x]!=-1)
{
next.found|=(1<<idx[x]);
}
}
if(next.found!=cur.found)
q.push(next);
}
}
}
}
int main()
{
int i,cnt=1;
#ifdef LOCAL
freopen("c:\\1.txt","r",stdin);
#endif
while(scanf("%d",&N)==1)
{
if(N==0) break;
memset(idx,-1,sizeof(idx));
ans.clear();
for(i=0; i<N; i++)
{
scanf("%d",&arr[i]);
ans.insert(arr[i]);
}
sort(arr,arr+N);
N = unique(arr,arr+N) - arr;
MAX=arr[N-1];
for(int i=0; i<N; i++)
idx[arr[i]] = i;
staus = (1<<N)-1;
bfs();
printf("Case %d:\n%d\n",cnt++,ans.size());
for(set<int>::iterator iter=ans.begin(); iter!=ans.end(); ++iter)
printf("%d ",*iter);
printf("\n");
}
return 0;
}
相关文章推荐
- DEDECMS修改文章TAG 给TAG加链接 去掉TAG字数限制
- c#遍历checkBox控件,并用MessageBox显示出来
- 卡榫函数实现API
- Leetcode87: Find Minimum in Rotated Sorted Array
- 019-OC特有语法-OC笔记
- 理解依赖注入(Dependency Injection)
- 剑指offer—把二叉树打印成多行
- break 和continue以及return的区别
- leetcode 21:Merge Two Sorted Lists(15-10-9)
- Generate Parentheses
- 018-继承-OC笔记
- 017-封装-OC笔记
- Sping面试题分析
- Ants (poj 3565 最小权匹配)
- Linux性能测试strace命令
- STM32--vs1053 WAV录音实现(wav保存在flash)
- 基于LNMP实现zabbix环境搭建
- Cocos2d-x中自定义XML的读取和写入
- 015-OC基础语法-OC笔记
- 016-类与对象-OC笔记