NEUQ-ACM预备队训练-week5-存图

前言与题解思路

这周的作业是存图,主要是图的vector存储加上DFS或BFS进行搜索

  • 第一题先用vector存储无向图,再从起点进行DFS搜索,记录下每次可以到达终点的路径,用s数组记录每个点属于的路径的条数,最后判断除了起始点之外的路径上的所有点,答案就是这些点中属于的路径的条数等于总可到达路径的条数的个数
  • 第二题我采用的是反向建边用vector存储有向图的方法,因为正向建图会导致最后几个测试点运行超时,然后从最大的点依次到最小的点进行DFS搜索,用A数组存储某点出发的最大点,最后正序输出A数组即可
  • 第三题因为要封锁全部的路,所以我们可以利用for循环,从每一个点开始,遍历它所能到达的全部点。因为河蟹有冲突,但是一条路总是有两个端点的,我们可以设置有河蟹1和河蟹2,在一个点若放置河蟹1,则将下一个点转为放置河蟹2而不是置为空,最后在河蟹的最终数目中加上河蟹1和河蟹2中较小的那个保证最终河蟹数目是最小的,同时,这种情况由于会对全部的点进行涂色,那么无解的情况就是有一条路上的两个端点被涂上了相同颜色

(1)危险系数

题目背景

抗日战争时期,冀中平原的地道战曾发挥重要作用。

题目描述

地道的多个站点间有通道连接,形成了庞大的网络。但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系。

我们来定义一个危险系数 D F ( x , y ) DF(x,y) DF(x,y)

对于两个站点 x x x y ( x ≠ y ) , y(x\neq y), y(x=y), 如果能找到一个站点 z z z,当 z z z 被敌人破坏后, x x x y y y 不连通,那么我们称 z z z 为关于 x , y x,y x,y 的关键点。相应的,对于任意一对站点 x x x y y y,危险系数 D F ( x , y ) DF(x,y) DF(x,y) 就表示为这两点之间的关键点个数。

本题的任务是:已知网络结构,求两站点之间的危险系数。

输入格式

输入数据第一行包含 2 2 2 个整数 n ( 2 ≤ n ≤ 1000 ) n(2 \le n \le 1000) n(2n1000) m ( 0 ≤ m ≤ 2000 ) m(0 \le m \le 2000) m(0m2000),分别代表站点数,通道数。

接下来 m m m 行,每行两个整数 u , v ( 1 ≤ u , v ≤ n , u ≠ v ) u,v(1 \le u,v \le n,u\neq v) u,v(1u,vn,u=v) 代表一条通道。

最后 1 1 1 行,两个数 u , v u,v u,v,代表询问两点之间的危险系数 D F ( u , v ) DF(u,v) DF(u,v)

输出格式

一个整数,如果询问的两点不连通则输出 − 1 -1 1

样例 #1

样例输入 #1

7 6
1 3
2 3
3 4
3 5
4 5
5 6
1 6

样例输出 #1

2

提示

时限 1 秒, 64M。蓝桥杯 2013 年第四届国赛

代码

#include<bits/stdc++.h>
using namespace std;

int n,m;
vector<int>G[1005];

int start1,end1;
bool vis[1005];
int s[1005];
int sum;

void DFS(int now) {
	if(now==end1) {
		sum++;
		for(int i=1; i<=n; i++) {
			if(vis[i]==true) {
				s[i]++;
			}
		}
		return;
	}
	for(int i=0; i<G[now].size(); i++) {
		int next=G[now][i];
		if(vis[next]==false) {
			vis[next]=true;
			DFS(next);
			vis[next]=false;
		}
	}
	return;
}
int main() {
	cin>>n>>m;
	for(int i=0; i<m; i++) {
		int u,v;
		cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	cin>>start1>>end1;
	vis[start1]=true;
	DFS(start1);
	if(sum==0){
		cout<<-1;
		return 0;
	}
	int ans=0;
	for(int i=1; i<=n; i++) {
		if(s[i]==sum) {
			ans++;
		}
	}
	ans-=2;
	cout<<ans;
	return 0;
}

(2)图的遍历

题目描述

给出 N N N 个点, M M M 条边的有向图,对于每个点 v v v,求 A ( v ) A(v) A(v) 表示从点 v v v 出发,能到达的编号最大的点。

输入格式

1 1 1 2 2 2 个整数 N , M N,M N,M,表示点数和边数。

接下来 M M M 行,每行 2 2 2 个整数 U i , V i U_i,V_i Ui,Vi,表示边 ( U i , V i ) (U_i,V_i) (Ui,Vi)。点用 1 , 2 , … , N 1,2,\dots,N 1,2,,N 编号。

输出格式

一行 N N N 个整数 A ( 1 ) , A ( 2 ) , … , A ( N ) A(1),A(2),\dots,A(N) A(1),A(2),,A(N)

样例 #1

样例输入 #1

4 3
1 2
2 4
4 3

样例输出 #1

4 4 3 4

提示

  • 对于 60 % 60\% 60% 的数据, 1 ≤ N , M ≤ 1 0 3 1 \leq N,M \leq 10^3 1N,M103
  • 对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 1 0 5 1 \leq N,M \leq 10^5 1N,M105

代码

#include<bits/stdc++.h>
using namespace std;

int N,M;
vector<int>G[100005];

int A[100005];

void DFS(int now,int max1){
	if(A[now]!=0)	return;
	A[now]=max1;
	for(int i=0;i<G[now].size();i++){
		int next=G[now][i];
		DFS(next,max1);
	}
}
int main() {
	cin>>N>>M;
	for(int i=0;i<M;i++){
		int u,v;
		cin>>u>>v;
		G[v].push_back(u);
	}
	for(int i=N;i>=1;i--){
		DFS(i,i);
	}
	for(int i=1;i<=N;i++){
		cout<<A[i]<<" ";
	}
	return 0;
}

(3)封锁阳光大学

题目描述

曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街。河蟹看到欢快的曹,感到不爽。河蟹决定封锁阳光大学,不让曹刷街。

阳光大学的校园是一张由 n n n 个点构成的无向图, n n n 个点之间由 m m m 条道路连接。每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在这些道路上刷街了。非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突。

询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突。

输入格式

第一行两个正整数,表示节点数和边数。
接下来 m m m 行,每行两个整数 u , v u,v u,v,表示点 u u u 到点 v v v 之间有道路相连。

输出格式

仅一行如果河蟹无法封锁所有道路,则输出 Impossible,否则输出一个整数,表示最少需要多少只河蟹。

样例 #1

样例输入 #1

3 3
1 2
1 3
2 3

样例输出 #1

Impossible

样例 #2

样例输入 #2

3 2
1 2
2 3

样例输出 #2

1

提示

【数据规模】
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 4 1\le n \le 10^4 1n104 1 ≤ m ≤ 1 0 5 1\le m \le 10^5 1m105,保证没有重边。

代码

#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int> map_nm[100005];
bool mapcheck[100005];
int ans[100005];
int x1, x2;
int num;
void DFS(int now, int color) {
	if (mapcheck[now])return;
	mapcheck[now] = true;
	ans[now] = color;
	if (ans[now] == 1) x1++;
	if (ans[now] == 2) x2++;
	for (int i = 0; i < map_nm[now].size(); i++) {
		int to = map_nm[now][i];
		if (mapcheck[to])continue;
		if (color == 1)color = 2;
		else color = 1;
		DFS(to, color);
		if (color == 1)color = 2;
		else color = 1;
	}
}
int main() {
	cin >> n >> m;
	while (m--) {
		int a, b;
		cin >> a >> b;
		map_nm[a].push_back(b);
		map_nm[b].push_back(a);
	}
	for (int i = 0; i < n; i++) {
		if (map_nm[i].empty() || mapcheck[i])continue;
		DFS(i, 1);
		num += min(x1, x2);
		x1 = 0;
		x2 = 0;
	}
	int flag = 1;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j< map_nm[i].size(); j++) {
			if (ans[i] == ans[map_nm[i][j]])
				flag = 0;
		}
	}
	if(flag==1)	printf("%d", num);
	else printf("Impossible");
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值