LA 3667 Ruler 两种不同形式的搜索来解决

来源:互联网 发布:农村淘宝亏了好几万 编辑:程序博客网 时间:2024/04/28 21:04

这题目让我对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;  }  



1 0
原创粉丝点击