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 间的每一条路径,将路径总数统计,并将被经过的点被经过总数加一。如果一个点被经过的次数与总路径条数相等,那么这一个点就是 u 和 v 的关键点。
注意:起点终点不要算,最后在结果上处理
#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;
}