【dfs/bfs+set+快速幂】swjtuOJ 2094
【注:交大的看到这篇文章要学会自己写,不要为了比赛而比赛!~】
题目大意
问题一:主人公去度假,问经过a^b天后是星期几(简单题)
问题二:一个天平,n个重物,每个物体的重量wi已知,问能称出的所有重量有多少种?
问题二要注意到天平两侧都可以放重物,每一个重物的权值都可以赋值为w,0,-w,相当于三分,我们知道二分可以用二进制位运算进行枚举,例如:枚举所有子集
int j,k,top=0;
int t = 1 << n;
for(int i = 0;i < t; ++ i){//位运算枚举子集,O(N*2^N)
j = i;
k = 0;
while(j){
if(j&1) printf("%d ",w[k]);
j >>= 1;
++ k;
}
printf("\n");
}
这道三分的问题直接搜索了,母函数解决不了(w太大存不下), 搜索dfs和bfs都可以,很裸的搜索了,去重用set神器!O(∩_∩)O~
【注意】求的和是负值也是有效的,abs后扔进set里面~~~
–
说一下思路
- 问题一:整数快速幂,题目1<=a,b<=10有误,a,b范围很大的
- 问题二:和之前说的思路一致,直接搜索,我写了两版,供读者参考,求出来的和扔进set容器里面自动去重了,最后输出set的大小和最后一个数值(自动排序后最后一个数肯定为所有物体重量w之和)
?set和map的比较:map最大优点是映射,对于存储数字序列,也有自动去重、自动排序的功能,还可以映射出该数字出现的次数(在值域之中it->second);set是不可重复的多元集合,最大特点在于去重,而且默认排序。总之,去重神器set Orz~
参考代码一:dfs
/*====================================*|* set去重+三种状态枚举子集:dfs + bfs*|
|* 两种状态可以用二进制位运算解决 *|
\*====================================*/
/*Author:Hacker_vision*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<set>
#define clr(k,v) memset(k,v,sizeof(k))
#define ll long long
#define eps 1e-8
using namespace std;
const int _max = 4e6 + 10;
const int mod = 7;
int a,b,n,w[20];
struct node{
int num;
ll sum;
};
set<ll>s;
void dfs(int deep,ll tot){//深度优先搜索
if(deep==n){
if(tot) s.insert(abs(tot));
return;
}
dfs(deep+1,tot);
dfs(deep+1,tot-w[deep]);
dfs(deep+1,tot+w[deep]);
}
ll quick_mod(ll a,ll b){//矩阵快速幂
ll ans = 1;
while(b){
if(b&1) ans = (ans*a)% mod;
b >>= 1;
a = (a * a) % mod;
}
return ans;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
#endif // ONLINE_JUDGE
while(scanf("%d%d",&a,&b)==2){
ll d = quick_mod((ll)a,(ll)b);
if(d%7==0||d%7==6) printf("800 ");
else printf("1000 ");
scanf("%d",&n);
for(int i = 0; i < n; ++ i){
scanf("%d",w+i);
}
s.clear();
dfs(0,0);
set<ll>::reverse_iterator it = s.rbegin();//反向迭代器
printf("%d %lld\n",s.size(),*it);
}
return 0;
}
参考代码二:bfs
/*====================================*|* set去重+三种状态枚举子集:dfs + bfs*|
|* 两种状态可以用二进制位运算解决 *|
\*====================================*/
/*Author:Hacker_vision*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<set>
#define clr(k,v) memset(k,v,sizeof(k))
#define ll long long
#define eps 1e-8
using namespace std;
const int _max = 4e6 + 10;
const int mod = 7;
int a,b,n,w[20];
struct node{
int num;
ll sum;
};
set<ll>s;
queue<node>Q;
void bfs(){ //广度优先搜索
node q;
q.num = 0;
q.sum = 0;
Q.push(q);
while(!Q.empty()){
q = Q.front();
Q.pop();
if(q.num==n){
if(q.sum>0) s.insert(q.sum);
continue; //return;最短路是return
}
node p;p.num = q.num + 1;
for(int i = 0; i < 3; ++ i){
if(i == 0) {
p.sum = q.sum ;
}
else if(i == 1){
p.sum = q.sum + w[q.num];
}
else p.sum = q.sum - w[q.num];
Q.push(p);
}
}
}
ll quick_mod(ll a,ll b){//矩阵快速幂
ll ans = 1;
while(b){
if(b&1) ans = (ans*a)% mod;
b >>= 1;
a = (a * a) % mod;
}
return ans;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
#endif // ONLINE_JUDGE
while(scanf("%d%d",&a,&b)==2){
ll d = quick_mod((ll)a,(ll)b);
if(d%7==0||d%7==6) printf("800 ");
else printf("1000 ");
scanf("%d",&n);
for(int i = 0; i < n; ++ i){
scanf("%d",w+i);
}
s.clear();
while(!Q.empty()) Q.pop();
bfs();
set<ll>::reverse_iterator it = s.rbegin();//反向迭代器
printf("%d %lld\n",s.size(),*it);
}
return 0;
}
- 加粗
Ctrl + B
- 斜体
Ctrl + I
- 引用
Ctrl + Q
- 插入链接
Ctrl + L
- 插入代码
Ctrl + K
- 插入图片
Ctrl + G
- 提升标题
Ctrl + H
- 有序列表
Ctrl + O
- 无序列表
Ctrl + U
- 横线
Ctrl + R
- 撤销
Ctrl + Z
- 重做
Ctrl + Y
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-09 08:35:53