NEUQ-ACM预备队week5

NEUQ-ACM预备队week5

知识点:图论

图是一个二元组 G = ( V ( G ) , E ( G ) ) G=(V(G), E(G)) G=(V(G),E(G)) ,由点集和边集组成

对于 V V V 中的每个元素,我们称其为 顶点 (Vertex)节点 (Node) ,简称 E ( G ) E(G) E(G) V ( G ) V(G) V(G) 各结点之间边的集合,称为 边集 (Edge set)

图有多种,包括 无向图 (Undirected graph)有向图 (Directed graph)混合图 (Mixed graph)

vector G[N];存图,链式

1.地道战(P1160)

思路:课程例题.

使用 dfs(深度优先搜索)求解,求出 u 到 v 间的每一条路径,将路径总数统计,并将被经过的点被经过总数加一。如果一个点被经过的次数与总路径条数相等,那么这一个点就是 uv 的关键点。

注意:起点终点不要算,最后在结果上处理

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
bool vis[N];
int st,ed,x,y,tot,m,n;
vector<int>G[N];
int cnt[N]; 

void dfs(int now){
	if(now==ed){
		tot++;
		for(int i=1;i<=n;i++){
			if(vis[i])
				cnt[i]++;//经过这个站点一次
		}
		return;
	}
	for(int i=0;i<G[now].size();i++)
	{
		int to=G[now][i];//取出下一个点 
		if(!vis[to]){//判断是否访问过
			vis[to]=true;
			dfs(to);//深入
			vis[to]=false;
		}
	}
	return;
}
int main(){
	cin>>n>>m;
	while(m--){
		cin>>x>>y;
		G[x].push_back(y);//无向图,双向都存储 
		G[y].push_back(x);
	}
	cin>>st>>ed;
	
	vis[st]=true;
	dfs(st);//搜索这两点间要经过的节点的个数 
	
	int ans=0;
	for(int i=1;i<=n;i++){//计算总结果数
		if(cnt[i]==tot){
			ans++;
		}
	}
	ans-=2;
	cout<<ans;
	return 0;
}

2.图的遍历(P3916)

反向建图+dfs

一开始傻傻dfs,果然不行.想到了反向建图的思路,但还是看了看题解,ac

!因为数组开小了,有四个RE.没看好数据范围检查了好久hhh

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,m,x,y;
vector<int>G[N];
int ans[N];//访问过的点的最大数 

void dfs(int now,int fa){
	if(ans[now]) return;//如果访问过,直接返回 
	ans[now]=fa;
	for(int i=0;i<G[now].size();i++){
			dfs(G[now][i],fa);
		}
	}

int main(){
	cin>>n>>m;//n为点数m为边数
	while(m--){
		cin>>x>>y;
		G[y].push_back(x);
	}//存反图 
	
	for(int i=n;i>=1;i--) if(!ans[i])dfs(i,i);
	
	for(int i=1;i<=n;i++) cout<<ans[i]<<' ';

	return 0;
}

3.封锁阳光大学(P1330)

染色法

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

vector<int>map[int(1e5) + 1];//图
queue<int>bfs_queue;
bool book[int(1e5) + 1] = { 0 };//标记物
bool paint_book[int(1e5) + 1] = { 0 };//染色

int bfs(int start) {//染色法
	int white_sum = 0, black_sum = 0;//统计白、黑节点的数量
	bfs_queue.push(start);
	book[start] = true;
	paint_book[start] = 1;//1为白色,0为黑色
	white_sum += 1;
	while (!(bfs_queue.empty())) {
		for (int i = 0; i < map[bfs_queue.front()].size(); i++) {
			if (!book[map[bfs_queue.front()][i]]) {//判断是否访问过

				bfs_queue.push(map[bfs_queue.front()][i]);
				book[map[bfs_queue.front()][i]] = true;

				if (paint_book[bfs_queue.front()]) {//队首节点为白色
					paint_book[map[bfs_queue.front()][i]] = 0;
					black_sum += 1;
				}
				else {//队首节点为黑色
					paint_book[map[bfs_queue.front()][i]] = 1;
					white_sum += 1;
				}
			}
			else {//访问过则判断颜色是否相异
				if (paint_book[bfs_queue.front()] == paint_book[map[bfs_queue.front()][i]])//相同
					return -1;//impossible
			}
		}
		bfs_queue.pop();
	}
	if (white_sum > black_sum)
		return black_sum;
	else
		return white_sum;
}

int main(){
	int n, m, sum = 0, u, v;//节点数、边数、河蟹总数、端点
	cin >> n >> m;

	for (int i = 0; i < m; i++){//存图
		cin >> u >> v;
		map[u].push_back(v);
		map[v].push_back(u);
	}

	for (int i = 1; i <= n; i++) {
		if (!(book[i])) {
			int ret = bfs(i);
			if (ret == -1) {
				cout << "Impossible";
				return 0;
			}
			else {
				sum += ret;
			}
		}
		
	}
	cout << sum;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值