C. The Tag Game
题解:
建一个树遍历一遍,标记节点的步数就可以了。
主要练习一下,建图建树,还是用vector方便,链式结构用不惯啊
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
#define mp make_pair
const int N=200010;
const long long INF=1e18;
const double eps=0.0000001;
const ll mod=1e9+7;
vector<int>E[N];///建立双向的图,实现遍历
vector<int>tree[N];///建立单向的树形结构,表明关系
int deg[N];///存树的高度
int pre[N];///存节点的父节点
void build(int x)///建树的方法
{
queue<int>q;
q.push(x);
deg[x]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(auto v:E[u])
{
if(deg[v]) continue;
deg[v]=deg[u]+1;
pre[v]=u;
q.push(v);
tree[u].push_back(v);
}
}
}
int vis[N];
void bfs1(int x)
{
queue<int>q;
q.push(x);
vis[x]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(auto v:E[u])
{
if(vis[v]) continue;
vis[v]=vis[u]+1;
q.push(v);
}
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n,m,v,u,x;
cin>>n>>x;
for(int i=1;i<=n-1;i++)//
{
cin>>u>>v;
E[u].push_back(v);
E[v].push_back(u);
}
build(1);
///本题默认1为根节点,如果根节点不确定或者不只一个
///可以通过入度判断,找到入度为0的点,后建立森林
bfs1(x);
int ans=0;
for(int i=1;i<=n;i++)
{
if(deg[i]>vis[i])
ans=max(ans,deg[i]);
}
cout<<(ans-1)*2<<endl;
}
D - Catch
题解:
判断是否为联通图:如果不联通是不可能到达所有点的。
判断是否为二分图:如果为二分图,不能达到相邻的点。
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<functional>
#include<set>
#include<map>
#include<stack>
#include<iterator>
#include<queue>
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
#define mp make_pair
const int N=1e6+10;
const long long INF=1e18;
const double eps=0.0000001;
const ll mod=1e9+7;
int n,m;
int u,v;
struct Edge{
int v,next;
}edge[N];
int cnt,head[N];
int color[N];
void init(){//初始化
cnt=0;
memset(head,-1,sizeof(head));
}
void addEdge(int u,int v){//建立无向无权图
edge[cnt]=Edge{v,head[u]};
head[u]=cnt++;
edge[cnt]=Edge{u,head[v]};
head[v]=cnt++;
}
bool dfs(int u,int c){//dfs遍历
color[u]=c;
for(int i=head[u];i!=-1;i=edge[i].next){//节点遍历
int v=edge[i].v;
if(color[v]==c){
return false;
}
if(color[v]==0&&!dfs(v,-c)){
return false;
}
}
return true;
}
void solve(){
memset(color,0,sizeof(color));
for(int i=0;i<n;i++){//遍历节点
if(color[i]==0){//当节点未染色进行二分判定
if(!dfs(i,1)){
printf("YES\n");
return;
}
}
}//如果都满足二分图的性质则此图为二分图
printf("NO\n");
}
int pre[N]; //每个结点
int ranks[N]; //树的高度
//初始化
void inits(int n) //对n个结点初始化
{
for(int i = 0; i <n; i++){
pre[i] = i; //每个结点的上级都是自己
ranks[i] = 1; //每个结点构成的树的高度为1
}
}
//改进查找算法:完成路径压缩,将x的上级直接变为根结点,那么树的高度就会大大降低
int Find_pre(int x) //查找结点x的根结点
{
if(pre[x] == x){ //递归出口:x的上级为x本身,即x为根结点
return x;
}
return pre[x] = Find_pre(pre[x]); //递归查找 此代码相当于 先找到根结点rootx,然后pre[x]=rootx
}
void unite(int x,int y)
{
int rootx, rooty;
rootx = Find_pre(x);
rooty = Find_pre(y);
if(rootx == rooty){
return ;
}
if(ranks[rootx] > ranks[rooty]){
pre[rooty] = rootx; //令y的根结点的上级为rootx
}
else{
if(ranks[rootx] == ranks[rooty]){
ranks[rooty]++;
}
pre[rootx] = rooty;
}
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t,k,p;
scanf("%d",&t);
p=t;
while(t--){
scanf("%d%d%d",&n,&m,&k);
init();inits(n);
while(m--){
scanf("%d%d",&u,&v);
unite(u,v);
addEdge(u,v);
}
int ans=0;
for(int i=0;i<n;i++)
if(Find_pre(i)==i) ans++;
if(ans==1)
{
printf("Case %d: ",p-t);
solve();
}
else
printf("Case %d: NO\n",p-t);
}
return 0;
}