危险系数
题目
实现
计算u,v之间的危险系数,就是要找到从u到v的全部路径中都会经过的点
我们可以通过:记录从u到v的路径数、记录每条路径经过的结点(令节点的值加一),最后如果有节点的值等于路径数时,表明这个节点就是一个危险系数,再找出所有这样的节点即可
代码块
#include<iostream>
#include<vector>
using namespace std;
const int N = 1005;
int n, m;
vector<int> map[N];
bool mapcheck[N];
int mapway[N];
int ans, st, ed;
void DFS(int now)
{
if (now == ed)
{
ans++;
for (int i = 1; i <= n; i++)
{
if (mapcheck[i])
{
mapway[i]++;
}
}
return;
}
for (int i = 0; i < map[now].size(); i++)
{
int to = map[now][i];
if (!mapcheck[to])
{
mapcheck[to] = 1;
DFS(to);
mapcheck[to] = 0;
}
}
return;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int a, b;
cin >> a >> b;
map[a].push_back(b);
map[b].push_back(a);
}
cin >> st >> ed;
mapcheck[st] = 1;
DFS(st);
int cnt=0;
for (int i = 1; i <= n; i++)
{
if (mapway[i] == ans)
{
cnt++;
}
}
cout << cnt-2;
return 0;
}
图的遍历
题目
实现
虽然题目表述为对每一个点v找到它能到达的编号最大的点,但是这种情况下需要判断它的每个终点孰大,所以我们利用反向存图,从大到小,给每个点填入其起点的值,这样最终点的值就必定是它的最大值
代码块
#include<iostream>
#include<vector>
using namespace std;
const int maxn = 1e5 + 5;
int n, m;
vector<int> map[maxn];
int ans[maxn];
//反向建边 从编号最大的数开始,反向搜图
//将这个点能到达的全部点上的ans赋上这个点的值
//同时比较是否比它之前赋得的值大
void DFS(int now, int max)
{
if (ans[now])return;
ans[now] = max;
for (int i = 0; i < map[now].size(); i++)
{
DFS(map[now][i], max);
}
}
int main()
{
cin >> n >> m;
while (m--)
{
int a, b;
//表示能从a到b,反向建边,令其从b到a;
cin >> a >> b;
map[b].push_back(a);
}
for (int i = n; i >= 1; i--)
{
//这里的两个参数与通常DFS只传出发点的情况不同
//这里类似于excel的绝对与相对应用,第二个参数令其为绝对引用值
DFS(i,i);
}
for (int i = 1; i <= n; i++)
printf("%d ", ans[i]);
return 0;
}
封锁阳光大学
题目
实现
因为要封锁全部的路,所以我们可以利用for循环,从每一个点开始,遍历它所能到达的全部点。如何实现封锁路呢?因为河蟹有冲突,但是一条路总是有两个端点的,我们可以设置有河蟹1和河蟹2,在一个点若放置河蟹1,则将下一个点转为放置河蟹2而不是置为空,最后在河蟹的最终数目中加上河蟹1和河蟹2中较小的那个保证最终河蟹数目是最小的,同时,这种情况由于会对全部的点进行涂色,那么无解的情况就是有一条路上的两个端点被涂上了相同颜色
代码块
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 1e4 + 5;
int n, m;
vector<int> map[maxn];
//check是否被走过,走过的点总是被涂过色的,无需继续涂色
bool mapcheck[maxn];
int ans[maxn];
//河蟹1和河蟹2的计数器
int cnt1, cnt2;
//最终河蟹数
int num;
void DFS(int now, int color)
{
if (mapcheck[now])return;
mapcheck[now] = true;
ans[now] = color;
//记录涂色种类
if (ans[now] == 1) cnt1++;
if (ans[now] == 2) cnt2++;
for (int i = 0; i < map[now].size(); i++)
{
int to = map[now][i];
if (mapcheck[to])continue;
//每次涂色时都需要注意色彩的转置,1变2,2变1
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[a].push_back(b);
map[b].push_back(a);
}
for (int i = 0; i < n; i++)
{
//点不存在或者已被遍历
if (map[i].empty() || mapcheck[i])continue;
DFS(i, 1);
num += min(cnt1, cnt2);
cnt1 = 0;
cnt2 = 0;
}
//判断是否有邻接点被涂同一种颜色
int flag = 1;
for (int i = 0; i < n; i++)
{
for (int j = 0; j< map[i].size(); j++)
{
if (ans[i] == ans[map[i][j]])
flag = 0;
}
}
if (flag)
printf("%d", num);
else printf("Impossible");
return 0;
}