搜索
目录:
P1036 [NOIP2002 普及组] 选数
P2392 kkksc03考前临时抱佛脚
P1025 [NOIP2001 提高组] 数的划分
P6201 [USACO07OPEN]Fliptile S
P1460 [USACO2.1]健康的荷斯坦奶牛 Healthy Holsteins
P1135 奇怪的电梯
P1763 埃及分数
PS:图的遍历用BFS和DFS搜索
//bfs
#include<iostream>
#include<queue>
using namespace std;
queue<int>q;
//使用邻接矩阵的BFS
void BFS(int u)
{
vis[u] = true;
q.push(u);
while(!q.empty())
{
int head = q.front();
q.pop();
for(int w = 1;w <= n;w++){
if(edge[v][w] && !vis[w]){
vis[w] = true;
q.push(w);
}
}
}
}
//用栈来实现
void dfs(int u)
{
vis[u] = 1;
for(int i = 1;i <= n;i++)
{
if(edge[u][i] && !vis[v]) dfs(i);
}
}
int main()
{
return 0;
}
P1036 [NOIP2002 普及组] 选数
[NOIP2002 普及组] 选数 - 洛谷
实力直接回炉重造!!!
我花了三小时调试这题,没想到,败在括号上!!!
#include<iostream>
using namespace std;
const int N = 30;
int a[N];
int n,k;
int ans;
bool is_prime(int x)
{
for(int i = 2;i * i <= x;i++)
if(x % i == 0)return false;
return true;
}
void dfs(int m,int sum,int sta)
{
if(m == k)
{
if(is_prime(sum)) ans++;
return;
}
for(int i = sta;i < n;i++)
dfs(m+1,sum+a[i],i+1);
return;
}
int main()
{
cin>>n>>k;
for(int i = 0;i < n;i++)
cin>>a[i];
dfs(0,0,0);
cout<<ans<<endl;
return 0;
}
P2392 kkksc03考前临时抱佛脚
kkksc03考前临时抱佛脚 - 洛谷
思路:枚举左右脑分别工作即可
#include<bits/stdc++.h>
using namespace std;
int a[5],b[5][36];//表示a[N]哪一科,而b[ ][ ]表示一科中有多少道题
int minn = -0x3f3f3f3f;
int ans;
int l,r;
void dfs(int p,int n)//p表示几道题
{
if(p > a[n])
{
minn = min(max(l,r),minn);
return;
}
l += b[n][p];
dfs(p+1,n);
l -= b[n][p];
r += b[n][p];
dfs(p+1,n);
r -= b[n][p];
}
int main()
{
for(int i = 1;i <= 4;i++)
{
cin>>a[i];
}
for(int i = 1;i <= 4;i++)
{
for(int j = 1;j <= a[i];j++)
{
cin>>b[i][j];
}
l = 0,r = 0;//两个头脑都还没开始工作
minn = 0x3f3f3f3f;
dfs(1,i);
ans += minn;
}
cout<<ans<<endl;
return 0;
}
P1025 [NOIP2001 提高组] 数的划分
[NOIP2001 提高组] 数的划分 - 洛谷
思路:
记录上一次划分所用的数,保证当前划分所用数不小于上次划分所用分数,当划分次数等于k时比较该次划分所得总分是否与n相同并记录次数。
#include<iostream>
using namespace std;
int n,k;
int cnt;
void dfs(int m,int sum,int sta)//m为上一次所划分的数,sum表示所得总份数,sta表示划分数中剩余的次数
{
//处理分完的部分
if(sta == k)
{
if(sum == n)
cnt++;
return;
}
for(int i = m;i <= n-sum;i++)//剪枝部分
dfs(i,sum+i,sta+1);
return;
}
int main()
{
cin>>n>>k;
dfs(1,0,0);
cout<<cnt<<endl;
return 0;
}
P6201 [USACO07OPEN]Fliptile S
[USACO07OPEN]Fliptile S - 洛谷
思路:
因为对于第i行(i>=2)的数字只取决于它正上方的数字(mp[i-1][j])是1还是0,因为这是mp[i-1][j]最后的一次修改机会,我们必须把它更改成0。
如果mp[i-1][j]=1,这个格子就必须要翻,如果mp[i-1][j]=0,这个格子就一定不能翻。当所有的数都按照规则翻完后,如果图内没有1存在则合法,否则return
枚举第一行的即可!
#include<iostream>
using namespace std;
const int INF = 20000007;
const int N = 30;
int a[N][N];
//因为对于第i行(i>=2)的数字只取决于它正上方的数字(a[i-1][j])是1还是0,因为这是a[i-1][j]最后的一次修改机会,我们必须把它更改成0.
//如果a[i-1][j]=1,这个格子就必须要翻,如果a[i-1][j]=0,这个格子就一定不能翻。
int n,m;
int ans[N][N],p[N][N],q[N][N];
int mxn = INF;
void dfs(int x)
{
if(x > m)
{
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
p[i][j] = q[i][j];
for(int i = 1;i <= m;i++)
if(a[1][i])
{
p[1][i] ^= 1,p[2][i] ^= 1;
p[1][i+1] ^= 1,p[1][i-1] ^= 1;
}
for(int i = 2;i <= n;i++)
for(int j = 1;j <= m;j++)
{
//重点来了!!!
if(p[i-1][j] == 1)
{
a[i][j] = 1;
p[i][j] ^= 1;
p[i][j+1] ^= 1;
p[i][j-1] ^= 1;
p[i+1][j] ^= 1;
p[i-1][j] ^= 1;
//四方位全翻一次
}
else a[i][j] = 0;
if(p[i-1][j])return;
}
bool flag = false;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
if(p[i][j])
{
flag = true;
break;
}
if(!flag)
{
int tot = 0;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
if(a[i][j])tot++;
if(tot >= mxn)return;
mxn = tot;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
ans[i][j] = a[i][j];
}
return;
}
for(int i = 0;i <= 1;i++)
{
a[1][x] = i;
dfs(x+1);
}
}
int main()
{
cin>>n>>m;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
cin>>q[i][j];
dfs(1);
if(mxn == INF)cout<<"IMPOSSIBLE";
else
{
for(int i = 1;i <= n;i++)
{
for(int j = 1;j < m;j++)
cout<<ans[i][j]<<" ";
cout<<ans[i][m]<<endl;
}
}
return 0;
}
P1460 [USACO2.1]健康的荷斯坦奶牛 Healthy Holsteins
P1460 [USACO2.1]健康的荷斯坦奶牛 Healthy Holsteins - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<bits/stdc++.h>
using namespace std;
const int N = 30;
int a[N],sl[N][N];//表示维他命的数量
int v,g;
int minn = 0x3f3f3f3f;
int cur[N];//表示当时枚举的子集选中了哪些饲料
int ans[N];//表示全局选中的哪些饲料
bool check(int x)
{
for(int i = 1;i <= v;i++)
{
int sum = 0;
for(int j = 1;j <= x;j++)
{
sum+=sl[cur[j]][i];
}
if(sum < a[i])
{
return false;
}
}
return true;
}
void dfs(int dq,int cnt)//dq当前枚举的饲料编号,cnt表示当前子集元素的总个数
{
if(dq == g+1)
{
if(check(cnt) == true)
{
if(minn > cnt)
{
minn = cnt;
for(int i = 1;i <= cnt;i++)
{
ans[i] = cur[i];
}
}
}
return;
}
if(dq <= g)
{
cur[cnt+1] = dq;
//选中
dfs(dq+1,cnt+1);
//不选
dfs(dq+1,cnt);
cur[cnt+1] = 0;
}
}
int main()
{
cin>>v;
for(int i = 1;i <= v;i++)
{
cin>>a[i];
}
cin>>g;
for(int i = 1;i <= g;i++)
{
for(int j = 1;j <= v;j++)
{
cin>>sl[i][j];
}
}
dfs(1,0);
cout<<minn<<" ";
for(int i = 1;i <= minn;i++)
{
cout<<ans[i]<<" ";
}
cout<<endl;
return 0;
}
P1135 奇怪的电梯
奇怪的电梯 - 洛谷
思路:直接dfs爆搜一边即可
我自己都服了,我会犯低级错误
没判断按键的数量是否会超过预期数量
//P1135 奇怪的电梯
//直接 dfs往下搜即可
//也可以转化为图的模式
#include<iostream>
using namespace std;
const int N = 220;
int a,b,n;
int K[N];
int cnt = 0x3f3f3f3f;
bool vis[N];
void dfs(int m,int sum)//m表示当前搜到的楼层,sum表示按钮次数
{
if(m == b) cnt = min(cnt,sum);
return;
vis[m] = 1;
//不越界就搜
if(m+K[m] <= n && !vis[m+K[m]]) dfs(m+K[m],sum+1);
if(m-K[m] >= 1 && !vis[m-K[m]]) dfs(m-K[m],sum+1);
vis[m] = 0;
return;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>a>>b;
for(int i = 1;i <= n;i++)
{
cin>>K[i];
}
vis[a] = 1;
dfs(a,0);
if(cnt != 0x3f3f3f3f) cout<<cnt<<endl;
else cout<<"-1"<<endl;
return 0;
}
P1763 埃及分数
埃及分数 - 洛谷
没开ll的后果!!!
警钟长鸣!!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e8+10;
ll sum[N];
ll a[N];
int ans;
bool dfs(ll mol,ll x,ll y)
{
if(mol == ans + 1)
{
if(x != 0)
{
return false;
}
if(sum[ans] > a[ans])
{
for(int i = 1;i <= ans;i++)
{
sum[i] = a[i];
}
}
return true;
}
bool flag = false;
for(ll i = max((ll)(ceil(y/x)),a[mol-1]+1);i <= ceil(y/x) * (ans - mol + 1);i++)//枚举分母
{
a[mol] = i;
ll dx = x * i - y;
ll dy = y * i;
ll g = __gcd(dx,dy);
dx /= g;
dy /= g;
if(dfs(mol+1,dx,dy))
{
flag = true;
}
}
return flag;
}
ll x,y;
int main()
{
scanf("%lld %lld",&x,&y);
for(ans = 1;;ans++)
{
sum[ans] = 0x3f3f3f3f;
if(dfs(1,x,y) == true)//搜到的每一个加数
{
break;
}
}
for(int i = 1;i <= ans;i++)
{
printf("%lld ",sum[i]);
}
return 0;
}