pat甲级真题分类-dfs

1

7-4 Chemical Equation (30 分)

/*
根据给出的反应方程式,选择其中最合适的,要求反应物不能由重复,剩下的就是些字符串的处理,以及dfs的处理过程

*/

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#pragma warning(disable:4996)//这是因为VS不能直接用scanf
using namespace std;

int N, M, K, r;
vector<int> R, P, rea, path;//R是反应物,P是要求生成的物质,rea是个工具数组...,path就是答案啦;
vector <vector<int> > react[110];//react里存放所有的反应,react[i][j][k]的意思是反应物 i 的第 j 优先级的反应式里面有 k 这种物质;上面的 path 里面存放每个 i 的 j;
bool use[110] = { false };//判断这个反应物有没有用过;

bool dfs(int i)
{
	if (i == M)
    {//只要走到最后一步就可以输出了,因为优先级已经排好了,走到最后就是最优先的;
		for (int j = 0; j < M; j++)
		{
			for (int t = 0; t < react[P[j]][path[j]].size(); t++)
			{
				if (t != 0) printf(" + ");
				printf("%02d", react[P[j]][path[j]][t]);
			}
			printf(" -> %02d\n", P[j]);
		}
		return 1;
	}
	
	for (int t = 0; t < react[P[i]].size(); t++)            //现在是去遍历每个反应物中的生成物
	{
		int j;
		for (j = 0; j < react[P[i]][t].size() && use[react[P[i]][t][j]] == 1; j++);//检查这个方案的反应物是不是都没被用
		if (j == react[P[i]][t].size())
        {
			for (j = 0; j < react[P[i]][t].size(); j++)//选了这个方案,把反应物用掉!
				use[react[P[i]][t][j]] = 0;
			path.push_back(t);
			if (dfs(i + 1))//看看下一个物质选哪个方案
				return 1;
			else {
				for (j = 0; j < react[P[i]][t].size(); j++)//这个方案不行,把反应物还回来!
					use[react[P[i]][t][j]] = 1;
				path.pop_back();
			}
		}
	}
	return 0;//这个物质的所有方案都不行,原因是之前的物质把反应物用掉了,要改之前的方案;
}

bool cmp(vector<int>a, vector<int>b) {
	for (int i = 0;; i++) {
		if (a[i] != b[i])
			return a[i] < b[i];
	}
}

int main()
{
	scanf("%d", &N);
	string s;
	for (int t = 0; t < N; t++)
    {
		scanf("%d", &r);
		R.push_back(r);
		use[r] = 1;
	}

	scanf("%d", &M);

	for (int t = 0; t < M; t++)
    {
		scanf("%d", &r);
		P.push_back(r);
		if (find(R.begin(), R.end(), r) != R.end())
		{//生成物同时也是反应物,加一个反应方案;
			rea.push_back(r);
			react[r].push_back(rea);
			rea.clear();
		}
	}


	scanf("%d\n", &K);

	while (K--)
    {
		getline(cin, s);
		int flag = 0;
		sscanf(s.c_str(), "%d", &r);            // 将字符串s读入int型变量r中

		rea.push_back(r);
		s = s.substr(3);                //从字符串下标为3的位置开始一直到字符串结束

		while (s[0] != '-')
        {
			sscanf(s.c_str(), "+ %d", &r);              //将所有的反应物读出来
			s = s.substr(5);
			rea.push_back(r);
		}

		sscanf(s.c_str(), "-> %d", &r);//找到最后的生成物
		react[r].push_back(rea);//储存方案;
		rea.clear();
	}


	for (int i = 0; i < M; i++)
    {    //给反应方案排序;
		sort(react[P[i]].begin(), react[P[i]].end(), cmp);
	}


	dfs(0);
	return 0;
}


2

7-3 Postfix Expression (25 分)



//注意这道题是按照图中所给的例子输出,并不是按照前序或者后序遍历法输出的
#include <iostream>
#include <cstring>
#include <unordered_map>
using namespace std;

const int N = 25;
int n;
string val[N];
bool has_father[N];
unordered_map<int, int> L, R;

string dfs(int u)
{
    string res;         //字符串res
    if (L.count(u))           //
        res = dfs(L[u]) + res;
    if (R.count(u))
        res = res + dfs(R[u]);
    if (!L.count(u) && R.count(u))      //没有左子树,但有右子树,所以要把val加到res左边
        res = val[u]+res;
    else         //左边有,右边没有,所以要把val加到右边   
        res = res + val[u];
    return "(" + res + ")";
}

int main()
{
    cin >> n;           //读入一个n

    for (int i = 1; i <= n; i++)            //i从1开始一直到n
    {
        int lc, rc;         //lc,rc代表左右儿子
        cin >> val[i] >> lc >> rc;
        if (lc != -1) L[i] = lc, has_father[lc] = true;
        if (rc != -1) R[i] = rc, has_father[rc] = true;
    }

    int root = 1;
    while (has_father[root])
        root++;                                        //找到根节点


    cout << dfs(root) << endl;

    return 0;
}

dfs+剪枝

7-1 Forever (20 分)

#include<cstdio>
#include<iostream>
#include<vector>
#include<cmath>
#include <algorithm>

using namespace std;

struct Node{
    int A;
    int n;
    Node(int _A,int _n)   //初始化
    {
        A = _A;
        n = _n;
    }
};

int K,M;// 总位数,总位数之和
vector<Node > result;

bool cmp(const Node &a,const Node &b)
{
    return a.n!=b.n?a.n<b.n:a.A<b.A;
}

int gcd(int a,int b)
{
    if(b==0)
        return a;
    return gcd(b,a%b);
}

bool isPrime(int n)
{
    if(n<=1) return false;
    for(int i=2; i*i<=n; i++)
        if(n%i==0)
            return false;
    return true;
}


int getDigitSum(int num)
{
    int m = 0;
    while (num!=0)
    {
        m += num%10;
        num /= 10;
    }
    return m;
}
/*
 * depth:当前深度,代表选择第几位,初始为0
 * m:当前已经选择的位数之和,比如选择了3次,分别是1,4,5,那么m=1+4+5=10
 * num:当前已经选择的位数所代表的数字,比如选择了3次,分别是1,4,5,那么num=145

 所要满足的条件:
 1.位数满足
 2.位数之和满足
 3.数字+1的位数之和满足
 4.n,m的最大公约数>2

 */
void DFS(int depth,int m,int num)   //初始值是0 0 0
{
    if(depth==K&&m==M)
    {
        int n = getDigitSum(num+1);// 得到n
        int G = gcd(m,n);
        if(G>2&&isPrime(G))
        {
            result.push_back({num,n});
        }
        return;
    }
    //剩下的这里代表 剪枝
    // 剩余最大值之和都小于所需要的,不可能有解
    if(m+9*(K-depth)<M||depth>K)
        return;
    for(int i=0;i<=9;i++)           //他所谓的第1位就是从左至右进行遍历
    {
        DFS(depth+1,m+i,num*10+i);      //这个就是每个数去遍历的
    }
}

int main()
{
    int N;
    scanf("%d",&N);             //读入N

    for(int i=0;i<N;++i)
    {
        scanf("%d %d",&K,&M);           //读入K和M,其中K代表数字的位数,M所有位数字之和

        printf("Case %d\n",i+1);        //输入第几个样例

        result.clear();         //对结果清空

        DFS(0,0,0);         //从初始值0 0 0 直接深搜

        sort(result.begin(), result.end(),cmp);     //排序

        for (auto &item : result)
        {
            printf("%d %d\n",item.n,item.A);
        }
        if (result.empty())
        {
            printf("No Solution\n");
        }
    }
    return 0;
}

7-4 Heap Paths (30 分)

#include <iostream>
using namespace std;

const int MAX_N = 1010;
int heap[MAX_N];
int path[MAX_N];
int n;
bool isMinHeap, isMaxHeap;
void DFS(int v, int step) {
    path[step] = heap[v];
    if (v * 2 > n) {
        for (int i = 0; i <= step; i++) {
            if (i) { 
                if (path[i] > path[i - 1]) isMinHeap = true;
                else if (path[i] < path[i - 1]) isMaxHeap = true;
                printf(" "); 
            }
            printf("%d", path[i]);
        }
        cout << endl;
        return;
    }
    if (v * 2 + 1 <= n) { 
        DFS(v * 2 + 1, step + 1); 
    }
    if (v * 2 <= n) { 
        DFS(v * 2, step + 1); 
    }
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> heap[i];
    }
    DFS(1, 0);
    if (isMaxHeap && isMinHeap) puts("Not Heap");
    else if (isMaxHeap) puts("Max Heap");
    else puts("Min Heap");
    return 0;
}

Eulerian Path



#include<iostream>
using namespace std;

const int maxn=511;

int g[maxn][maxn];

int d[maxn];

int n,m;

bool st[maxn];

int dfs(int u)
{
    st[u]=true;

    int res=1;
    for(int i=1; i<=n; i++)
        if(!st[i] && g[u][i])
            res+=dfs(i);

    return res;

}

int main()
{
    cin >> n >> m;
    for(int i=0; i<m; i++)
    {
        int a,b;
        cin >> a >> b;
        g[a][b]=g[b][a]=true;
        d[a]++;
        d[b]++;
    }

    int cnt=dfs(1);

    for(int i=1; i<=n; i++)
    {
        if(i!=1)
            cout << " ";
        cout << d[i];
    }

    cout << endl;

    if(cnt==n)
    {
        int s=0;
        for(int i=1; i<=n; i++)
            if(d[i]%2)
                s++;
        if(s==0)
            cout << "Eulerian" << endl;
        else if(s==2)
            cout << "Semi-Eulerian" << endl;
        else
            cout << "Non-Eulerian" << endl;
    }
    else
        cout << "Non-Eulerian" << endl;

    return 0;

}

Complete Binary Tree


#include<iostream>
#include<cstring>
using namespace std;

const int maxn=22;

int n;

int l[maxn],r[maxn];

bool has_father[maxn];

int maxk,maxid;

int dfs(int u,int k)
{
    if(u==-1)
        return 0;
    if(k>maxk)
    {
        maxk=k;
        maxid=u;
    }
    dfs(l[u],k*2);
    dfs(r[u],k*2+1);
}

int main()
{
    cin >> n;
    memset(l,-1,sizeof l);
    memset(r,-1,sizeof r);
    string a,b;
    for(int i=0; i<n; i++)
    {
        cin >> a >> b;
        if(a!="-")
            l[i]=stoi(a),has_father[l[i]]=true;
        if(b!="-")
            r[i]=stoi(b),has_father[r[i]]=true;
    }

    int root=0;

    while(has_father[root])
        root++;

    dfs(root,1);

    if(maxk==n)
    {
        cout << "YES" << " " << maxid;
    }
    else
    {
        cout << "NO" << " " << root;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值