1.CF601A The Two Routes
一个图有两种路,有这种路就没有那种路,求走两种路达到终点的时间
原图和补图跑Floyd判断联通即可
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=405,inf=0x3f3f3f3f;
int dis1[maxn][maxn],dis2[maxn][maxn];
int main(){
memset(dis1,inf,sizeof dis1);
memset(dis2,inf,sizeof dis2);
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
dis1[x][y]=1;
dis1[y][x]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dis1[i][j]==inf){
dis2[i][j]=dis2[j][i]=1;
}
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis1[i][j]=min(dis1[i][j],dis1[i][k]+dis1[k][j]);
}
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis2[i][j]=min(dis2[i][j],dis2[i][k]+dis2[k][j]);
}
}
}
if(dis1[1][n]==inf||dis2[1][n]==inf)printf("-1\n");
else{
printf("%d\n",max(dis1[1][n],dis2[1][n]));
}
return 0;
}
2.CF763A Timofey and a tree
选一个点,其左子树所有颜色必须相同,右子树所有颜色必须相同
根据题目要求可知,最多只能有三种情况,极限情况就是根,两颗子树分别为不同颜色
找一个点 其所连的所有边与其颜色不同的数量==所有连着两个不同颜色的边的数量,作为根节点,即可满足题目要求
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
unordered_set<int>st;
int col[maxn];
int ans[maxn],sum;
int a[maxn],b[maxn];
int main(){
int n;
cin>>n;
for(int i=1;i<=n-1;i++){
int u,v;
cin>>a[i]>>b[i];
}
for(int i=1;i<=n;i++){
cin>>col[i];
}
for(int i=1;i<=n;i++){
if(col[a[i]]!=col[b[i]]){
sum++;
ans[a[i]]++;
ans[b[i]]++;
}
}
for(int i=1;i<=n;i++){
if(ans[i]==sum){
printf("YES\n");
printf("%d",i);
return 0;
}
}
printf("NO");
}
3.CF780C Andryusha and Colored Balloons
任意一个点与其距离为2以内的点颜色不能相同,求最少用的总颜色数量
直接dfs即可
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int col[maxn],f[maxn];
int vis[maxn];
int n,m,mm;
vector<int>e[maxn];
inline void add(int u,int v){
e[u].push_back(v);
}
void dfs(int u,int fa){
int now=0;
for(auto v:e[u]){
if(v==fa)continue;
++now;
while(now==col[u]||now==col[fa])now++;
col[v]=now;
}
for(auto v:e[u]){
if(v==fa)continue;
dfs(v,u);
}
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
vis[u]++;
vis[v]++;
mm=max({mm,vis[u],vis[v]});
}
col[1]=1;
f[1]=1;
dfs(1,1);
cout<<mm+1<<endl;
for(int i=1;i<=n;i++){
printf("%d ",col[i]);
}
return 0;
}
4.CF246D Colorful Graph
选一种颜色,与其相连且颜色与其不同的点的颜色种类最小
因为要去重,所以用set保存即可,不同的数量相同的话输出点数最小的点
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=1e5+5;
int col[maxn],ans[maxn];
set<int>st[maxn];
vector<int>e[maxn];
int mm;
int main(){
cin>>n>>m;
int nb=0x7f7f7f7f;
for(int i=1;i<=n;i++){
cin>>col[i];
nb=min(nb,col[i]);
}
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
if(col[x]!=col[y]){
st[col[x]].insert(col[y]);
st[col[y]].insert(col[x]);
}
}
for(int i=1;i<=n;i++){
if(st[col[i]].size()>st[nb].size()){
nb=col[i];
}
}
cout<<nb;
}
5.CF369C Valera and Elections
给一棵树,选一些点,修复其到根节点的所有路径,问最少要选多少个点
是一个很水的题,由于太菜wa了
标记子树(包括自己)权为1的点输出即可
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
typedef pair<int,int>pii;
vector<pii>e[maxn];
int size[maxn];
vector<int>jl;
int n,m;
void dfs(int u,int fa){
int v,w;
int now=size[u];
for(auto x:e[u]){
v=x.first;
w=x.second;
if(v==fa)continue;
size[v]+=w-1;
dfs(v,u);
size[u]+=size[v];
}
if(now==1&&size[u]==1){
jl.push_back(u);
}
}
int main(){
cin>>n;
for(int i=1;i<n;i++){
int u,v,w;
cin>>u>>v>>w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
dfs(1,0);
cout<<jl.size()<<endl;
for(auto x:jl){
printf("%d ",x);
}
}
6.CF1006E Military Problem
求 u u u的子树 d f s dfs dfs序为 k k k的点
一个好题,一开始写了个暴力,一看 1 e 9 1e9 1e9的数据范围就想到肯定要把树的信息先预处理出来
可是基础太烂不知道怎么写
记录每个点的 d f n dfn dfn,记录第 t t t个遍历的到的是哪个点,如果子树 s i z e > = k size>=k size>=k的话输出 i d [ d f n [ u ] + k − 1 ] id[dfn[u]+k-1] id[dfn[u]+k−1],否则输出 − 1 -1 −1
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=2e5+5;
vector<int>e[maxn];
int f[maxn],size[maxn];
int cnt,k;
int t;
int dfn[maxn];
int id[maxn];
void dfs(int u){
dfn[u]=++t;
id[t]=u;
for(auto v:e[u]){
dfs(v);
size[u]+=size[v];
}
}
int main(){
int q;
cin>>n>>q;
size[1]=1;
for(int i=2;i<=n;i++){
int x;
cin>>x;
f[i]=x;
size[i]=1;
e[x].push_back(i);
}
dfs(1);
while(q--){
int u;
cin>>u>>k;
printf("%d\n",k<=size[u]?id[dfn[u]+k-1]:-1);
}
return 0;
}
7.CF659E New Reform
给一个无向图,求其边变为有向后最少有多少个点不能到达
一开始没有读懂真意,其实就是要找环,如果一个联通分量边数大于等于点数的话,一定会存在环,学到了一种用并查集判环的好方法
如果两个点不属于同一集合,合并,如果属于同一集合,标记该集合为有环的连通分量
输出无环的连通分量数量即可
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=2e5+5;
int f[maxn],vis[maxn];
int find(int x){
if(f[x]==x)return x;
else return f[x]=find(f[x]);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
f[i]=i;
}
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
int fx=find(x);
int fy=find(y);
if(fx==fy){
vis[x]=vis[y]=vis[fx]=vis[fy]=1;
}
else{
f[fx]=fy;
if(vis[x]||vis[y]||vis[fx]||vis[fy]){
vis[x]=vis[y]=vis[fx]=vis[fy]=1;
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
if(f[i]==i&&!vis[i])ans++;
}
cout<<ans;
}
8.CF639B Bear and Forgotten Tree 3
构造一棵n个点,深度h,最长链为d的树
先特判不成立的情况,如果直径>树高*2,必不可能成立
再如果直径和树高为1而节点数>2,必大于1,不成立
1.然后开始构造,先构造出刚好为树高的子树
2.再构造出另外一颗子树,让直径刚好满足
最后将所有的节点都连在1的叶子节点的父亲上即可
#include<bits/stdc++.h>
using namespace std;
int n,m,d,h;
const int maxn=2e5+5;
int main(){
cin>>n>>d>>h;
if(d>h*2||(h==d && d==1 && n>2)){
printf("-1");
return 0;
}
int i;
for(i=1;i<=h;i++){
printf("%d %d\n",i,i+1);
}
int j=1;
for(i=h+2;i<=d+1;i++){
printf("%d %d\n",j,i);
j=i;
}
for(i=d+2;i<=n;i++){
printf("%d %d\n",h,i);
}
return 0;
}
9.CF731C Socks
有n只袜子,k种颜色,在m天中,问最少修改几只袜子的颜色,可以使每天穿的袜子左右两只都同颜色
转化题意:求所有不想交集合中,各集合中,总袜子数 − - −与出现次数最多颜色不同颜色的袜子数
并查集+set去重,记录出现颜色出现次数之后要减掉,不能每次 m e m s e t memset memset此 v i s vis vis数组,会 T L E TLE TLE
#include<bits/stdc++.h>
using namespace std;
int n,m,tt,t,k;
const int maxn=2e5+5;
int col[maxn],f[maxn],vis[maxn];
int rr[maxn];
vector<int>e[maxn];
unordered_set<int>st;
int find(int x){
if(f[x]==x)return x;
return f[x]=find(f[x]);
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
f[i]=i;
}
for(int i=1;i<=n;i++){
cin>>col[i];
}
int sum=0;
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
if(!rr[x])rr[x]=1,sum++;
if(!rr[y])rr[y]=1,sum++;
int fx=find(x);
int fy=find(y);
if(fx!=fy){
f[fx]=fy;
}
}
for(int i=1;i<=n;i++){
e[find(i)].push_back(i);
st.insert(find(i));
}
for(auto u:st){
if(e[u].size()==1)continue;
int ans=0;
for(auto x:e[u]){
vis[col[x]]++;
ans=max(vis[col[x]],ans);
}
for(auto x:e[u]){
vis[col[x]]--;
ans=max(vis[col[x]],ans);
}
sum-=ans;
}
cout<<sum;
return 0;
}
10.CF939D Love Rescue
题意:给定两个长度为n的由小写字母组成的字符串
每次可以花费1的代价,指定两个字母,把其中一个全部变为另一个
求使两个字符串相同的最小花费
exo me?
#include<bits/stdc++.h>
using namespace std;
int n,m,tt,t,k;
const int maxn=2e5+5;
int f[maxn],vis[maxn];
pair<char,char>e[maxn];
string s1,s2;
int find(int x){
if(f[x]==x)return x;
return f[x]=find(f[x]);
}
int main(){
cin>>n;
for(int i=0;i<maxn;i++){
f[i]=i;
}
cin>>s1>>s2;
int cnt=0;
for(int i=0;i<n;i++){
char ss1=s1[i];
char ss2=s2[i];
int f1=find(ss1);
int f2=find(ss2);
if(f1!=f2){
f[f1]=f2;
cnt++;
e[cnt]={s1[i],s2[i]};
}
}
cout<<cnt<<endl;
for(int i=1;i<=cnt;i++){
cout<<e[i].first<<" "<<e[i].second<<endl;
}
return 0;
}
11.CF1133F1 Spanning Tree with Maximum Degree
给出了一个由n个顶点和m条边组成的无向无权连通图。它保证在给定的图中没有自环或重边。
你的任务是找到这个图的一棵生成树,使得树上顶点的最大度数尽可能地大。回忆一下,顶点的度数是与之关联的边的数量
思路:找到度数最大的点dfs输出一遍图即可
#include<bits/stdc++.h>
using namespace std;
int n,m,ans;
constexpr int maxn=2e5+5;
int du[maxn],mm,nb,vis[maxn];
vector<int>e[maxn];
void dfs(int u){
vis[u]++;
for(auto v:e[u]){
if(vis[v])continue;
vis[v]++;
printf("%d %d\n",u,v);
}
for(auto v:e[u]){
if(vis[v]>1)continue;
vis[v]++;
dfs(v);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
du[u]++;
du[v]++;
if(mm<du[u]){
mm=du[u];
nb=u;
}
if(mm<du[v]){
mm=du[v];
nb=v;
}
}
dfs(nb);
return 0;
}
12.CF986A Fair
每个点有自己的颜色,求每个点到s种不同颜色点的距离和
记录同一种颜色的所有点,对每一种颜色的点进行bfs,求得每种颜色到其他所有颜色的最小距离,排序后累加即可
#include<bits/stdc++.h>
using namespace std;
int n,m,k,s,ans;
constexpr int maxn=1e5+5;
int col[maxn];
int dis[maxn][105];
vector<int>e[maxn];
vector<int>jl[105];
int main(){
cin>>n>>m>>k>>s;
for(int i=1;i<=n;i++){
cin>>col[i];
jl[col[i]].push_back(i);
}
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
memset(dis,-1,sizeof dis);
for(int i=1;i<=k;i++){
queue<int>q;
for(auto v:jl[i]){
q.push(v);
dis[v][i]=0;
}
while(!q.empty()){
int u=q.front();
q.pop();
for(auto v:e[u]){
if(dis[v][i]==-1){
dis[v][i]=dis[u][i]+1;
q.push(v);
}
}
}
}
for(int i=1;i<=n;i++){
ans=0;
sort(dis[i]+1,dis[i]+1+k);
for(int j=1;j<=s;j++){
ans+=dis[i][j];
}
printf("%d ",ans);
}
return 0;
}
13.CF131D Subway
给出一个 n个点,n 条边的无向无权图,图上每条边的长度为 1,保证图中有且仅由一个环。
你的任务是求出每一个点到环(环上任意一点)的最短路径长度
学到了一个新东西:基环树,就比普通的树多了一个环
用拓扑排序可以找到环上的所有点,再把环上的点作为起点进行spfa求出到其他所有点的最短距离即可
#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
constexpr int maxn=10005,inf=0x3f3f3f3f;
int ru[maxn];
int dis[maxn],inque[maxn];
vector<int>e[maxn];
inline void topo(){
queue<int>q;
for(int i=1;i<=n;i++){
if(ru[i]==1)q.push(i);
}
while(!q.empty()){
int u=q.front();
q.pop();
for(auto v:e[u]){
if(ru[v]<=1)continue;
ru[v]--;
if(ru[v]==1)q.push(v);
}
}
}
inline void spfa(){
queue<int>q;
memset(dis,inf,sizeof dis);
for(int i=1;i<=n;i++){
if(ru[i]>=2)q.push(i),dis[i]=0,inque[i]=1;
}
while(!q.empty()){
int u=q.front();
q.pop();
inque[u]=0;
for(auto v:e[u]){
if(ru[v]>=2)continue;
if(dis[v]>dis[u]+1){
dis[v]=dis[u]+1;
if(!inque[v]){
inque[v]=1;
q.push(v);
}
}
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
ru[u]++;
ru[v]++;
}
topo();
spfa();
for(int i=1;i<=n;i++){
cout<<dis[i]<<" ";
}
return 0;
}
14.CF954D Fight Against Traffic
求最多可以加上多少边,s到t的距离不会缩短
用Floyd求出所有点的距离后,枚举判断即可
初始化不能直接全部赋值为inf,因为要判断两点间是否有边
#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
constexpr int maxn=1005,inf=0x3f3f3f3f;
int dis[maxn][maxn];
int main(){
cin>>n>>m>>s>>t;
// memset(dis,inf,sizeof dis);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j)dis[i][j]=inf;
}
}
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
dis[u][v]=1;
dis[v][u]=1;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
int ans=0;
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++){
if(dis[i][j]!=1&&(min(dis[s][i]+dis[j][t],dis[s][j]+dis[i][t])+1>=dis[s][t])){
ans++;
}
}
}
cout<<ans;
return 0;
}
15.CF34D Road Map
给定一棵树,并给定一个根,现在要换一个根,求换根后每个点的父节点
输入:第一行 节点个数 原根 新根 第二行 除原根节点外每个节点的父节点
输出:除新根节点外每个节点的父节点
思路:直接dfs
#include<bits/stdc++.h>
using namespace std;
int n,m,s,t;
constexpr int maxn=1e5+5,inf=0x3f3f3f3f;
vector<int>e[maxn];
int f[maxn];
int r1,r2;
void dfs(int u,int fa){
for(auto v:e[u]){
if(v!=fa){
f[v]=u;
dfs(v,u);
}
}
}
int main(){
cin>>n>>r1>>r2;
for(int i=1;i<=n;i++){
if(i==r1)continue;
int x;
cin>>x;
e[i].push_back(x);
e[x].push_back(i);
}
dfs(r2,0);
for(int i=1;i<=n;i++){
if(i==r2)continue;
cout<<f[i]<<" ";
}
}