zoukankan      html  css  js  c++  java
  • BFS练习

    1. 给定$d,k$, 求最小的被$d$整除, 且各数位仅有$k$和$0$组成的数. $(1le kle 9,1le nle 1e6)$

    从高位到低位$BFS$, BFS求出字典序最小的方案.

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define x first
    #define y second
    using namespace std;
    typedef pair<int,int> pii;
    
    const int N = 1e6+10;
    queue<int> q;
    int d, k, vis[N];
    pii pre[N];
    
    void dfs(int x) {
    	if (pre[x].x!=-1) dfs(pre[x].x);
    	printf("%d", pre[x].y);
    }
    
    int main() {
    	scanf("%d%d", &d, &k);
    	q.push(k%d);
    	vis[k%d] = 1;
    	pre[k%d] = pii(-1,k);
    	while (q.size()) {
    		int u = q.front(); q.pop();
    		for (int i=0; i<=k; i+=k) {
    			int v = (u*10+i)%d;
    			if (!vis[v]) {
    				vis[v] = 1;
    				pre[v] = pii(u,i);
    				q.push(v);
    			}
    		}
    	}
    	dfs(0),puts("");
    }
    

    2. 被$d$整除, 数位和为$s$的数. (CF 1070A)

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define x first
    #define y second
    using namespace std;
    typedef pair<int,int> pii;
    
    queue<pii> q;
    int d, s, vis[555][5050];
    pii pre[555][5050];
    
    void dfs(int x, int y) {
    	if (x||y) {
    		dfs(pre[x][y].x,pre[x][y].y);
    		printf("%d",y-pre[x][y].y);
    	}
    }
    
    int main() {
    	scanf("%d%d", &d, &s);
    	q.push(pii(0,0));
    	vis[0][0] = 1;
    	while (q.size()) {
    		pii u = q.front(); q.pop();
    		REP(i,0,9) {
    			pii v((u.x*10+i)%d,u.y+i);
    			if (v.y<=s&&!vis[v.x][v.y]) {
    				q.push(v);
    				pre[v.x][v.y] = u;
    				vis[v.x][v.y] = 1;
    			}
    		}
    	}
    	if (!vis[0][s]) return puts("-1"),0;
    	dfs(0,s),puts("");
    }
    

    3. 给定$k$种浓度的水, 每种数量无限, 求混合为浓度$n$最少要多少杯.

    容易发现答案序列$a_i$满足$sum (a_i-n)=0$, 从而转化为$BFS$求最小环.

    但是有一个问题是$sum (a_i-n)$的范围, 测试一下发现只要保证每步都在$[-1000,1000]$一定最优, 考虑证明.

    只需要证明 任意一个最优解均可通过重排, 使得每一步的和都在$[-1000,1000]$即可.

    考虑一个最优方案, 假设当前的$s>0$, 考虑添加一个数$t>0$.

    不合法当且仅当$s+t>1000$, 考虑调整后面负数的位置, 使得方案合法.

    若剩余负数存在一个$x$,有$-xge t$, 那么直接转移为$s+x+t$即可.

    否则剩余负数全在范围$[-t+1,0)$内.

    并且剩余负数总和绝对值一定不少于$s+t$(合法方案保证总和为$0$).

    这样的话不断选负数, 直到$s+sum x + t le 1000$, 这样一定合法.

    这是因为调整过程中, 最坏情况是和变为$s+sum x=1001-t$, 然后添加一个最小数得到$s+sum x=1002-2t>-1000$, 满足条件.

    所以结论成立.

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    using namespace std;
    
    const int N = 1e5+10;
    int n, k, a[N];
    int v[N], d[N], *dis = d+5010, *vis = v+5010;
    queue<int> q;
    
    int main() {
    	scanf("%d%d", &n, &k);
    	REP(i,1,k) { 
    		scanf("%d", a+i);
    		a[i] -= n;
    		if (vis[a[i]]) {
    			--i, --k;
    			continue;
    		}
    		vis[a[i]] = 1;
    		dis[a[i]] = 1;
    		q.push(a[i]);
    	}
    	while (q.size()) {
    		int u = q.front(); q.pop();
    		REP(i,1,k) {
    			int v = u+a[i];
    			if (abs(v)>1000) continue;
    			if (!vis[v]) {
    				vis[v] = 1;
    				dis[v] = dis[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	printf("%d
    ", vis[0]?dis[0]:-1);
    }
    
  • 相关阅读:
    Linux系统中DHCP的配置
    Linux系统下第三方软件安装实例
    Linux系统在启动过程中mbr主引导程序被破坏的解决方案
    Linux系统在启动过程中启动级别发生错误的解决办法
    Linux系统下超级用户密码的修改
    Linux系统在启动过程中内核文件丢失的解决方法
    Linux系统在启动过程中grub引导文件丢失的解决方法
    Linux之FTP服务
    Linux之LVM设备的管理
    Linux下设备的基本管理
  • 原文地址:https://www.cnblogs.com/uid001/p/11118814.html
Copyright © 2011-2022 走看看