您的位置:首页 > 其它

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

2015-10-08 21:40 183 查看
这题目让我对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
)//要比最大小
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: