阶段小结(南昌理工学院acm集训队)

优先队列

优先队列就是让优先级高的出列。它是队列和排序的组合,不仅可以储存数据,还可以将这些数据按照设定的规则进行排序。每次push和pop操作,优先队列都会动态调整,把优先级最高的元素放在前面。
正因为优先队列这种神奇的性质,有些题目配合优先队列会有奇效

定义:priority_queue<Type, Container, Functional>

比较方式默认用operator< , , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。(也就是默认非升序)
比较函数例子


struct cmp1
{
	bool operator ()(int& a, int& b)
	{
		return a > b;//最小值优先     
	}
};

支持的操作:
q.empty() //如果队列为空,则返回true,否则返回false
q.size() //返回队列中元素的个数
q.pop() //删除队首元素,但不返回其值
q.top() //返回具有最高优先级的元素值,但不删除该元素
q.push(item) //在基于优先级的适当位置插入新元素

next_permutation()

求下一个排列组合的函数next_permutation().
例如3个字符a.b.c组成的序列,next_permutation()能按字典序返回6个组合,即abc,acb,bac,bca,cab,cba

例 HDU1027

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include <vector>
#include <cmath>

using namespace std;

int a[1001] = {0};

int main()
{
	int n, m;
	while (cin >> n >> m) {
		for (int i = 1; i <= n; i++) {//生成一个字典序最小的序列
			a[i] = i;
		}
		int b = 1;
		do {
			if (b == m)break;
			b++;
		} while (next_permutation(a + 1, a + n + 1));
		for (int i = 1; i < n; i++) {
			cout << a[i] << " ";
		}
		cout << a[n] << endl;



	}
	return 0;
}

拓扑排序

定义
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

步骤
从DGA图中找到一个没有前驱的顶点输出。(可以遍历,也可以用优先队列维护)
删除以这个点为起点的边。(它的指向的边删除,为了找到下个没有前驱的顶点)
重复上述,直到最后一个顶点被输出。如果还有顶点未被输出,则说明有环

例 HDU3342

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include <vector>
#include <cmath>


using namespace std;
const int maxn = 1000;
vector<int>G[maxn];
int n, m;
int in[maxn];
bool topo() {
    queue<int>Q;
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        if (in[i] == 0)
            Q.push(i);
    }
    while (!Q.empty()) {
        int u = Q.front();
        Q.pop();
        sum++;
        for (int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            --in[v];
            if (in[v] == 0)
                Q.push(v);
        }
    }
    return sum == n;
}
int main()
{
    int u, v;
    while (scanf("%d%d", &n, &m)) {
        if (n == 0)
            break;
        memset(in, 0, sizeof(in));
        for (int i = 1; i <= n; i++) {
            G[i].clear();
        }
        for (int i = 1; i <= m; i++) {
            scanf("%d%d", &u, &v);
            u++;
            v++;///标号从1开始
            G[u].push_back(v);
            in[v]++;
        }
        if (topo() == 1) {
            puts("YES");
        }
        else {
            puts("NO");
        }
    }
    return 0;
}

并查集模板

这是我以前用的朴素写法的优化版

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include <vector>
#include <cmath>

using namespace std;

const int maxn = 1050;
int s[maxn];
int height[maxn];


void init_set() {
	for (int i = 1; i <= maxn; i++) {
		s[i] = i;
		height[i] = 0;
	}
}

int find_set(int x) {//并查集内查找
	if (x != s[x])s[x] = find_set(s[x]);
	return s[x];

	//非递归做法
	/*int r = x;
	while (s[r] != r)r = s[r];
	int i = x, j;
	while (i != r) {
		j = s[i];
		s[i] = r;
		i = j;
	}
	return r;*/
}




void union_set(int x, int y) {//合并
	x = find_set(x);
	y = find_set(y);
	if (height[x] == height[y]) {
		height[x] = height[y] + 1;
		s[y] = x;
	}
	else {
		if (height[x] < height[y])s[x] = y;
		else s[y] = x;
	}
}

int main()
{
	int t, n, m, x, y;
	cin >> t;
	while (t--) {
		cin >> n >> m;
		init_set();
		for (int i = 1; i <= m; i++) {
			cin >> x >> y;
			union_set(x, y);//x认识y,把他们合并起来
		}
		int ans = 0;
		for (int i = 1; i <= n; i++)
			if (s[i] == i)
				ans++;
		cout << ans << endl;
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值