这题目让我对bfs有更加深刻的认识了,好题一枚。
解法有两种,一种是递增暴搜,一种是常规的队列搜索
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[n])//要比最大小 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[n]-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[n]; 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; }