正睿OI补题(搜索)

搜索

目录:

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值