A - 图的存储与出边的排序
vector存图,排序后输出
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,m;
vector<int>g[N];
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++) g[i].clear();
for(int i=1;i<=m;i++){
int u,v;cin>>u>>v;
g[u].push_back(v);
}
for(int i=1;i<=n;i++) sort(g[i].begin(),g[i].end());
for(int i=1;i<=n;i++){
for(int v:g[i]) cout<<v<<" ";
cout<<'\n';
}
}
int main()
{
//freopen("a.txt","r",stdin);
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t;cin>>t;
while(t--){solve();}
return 0;
}
B - 拓扑排序 / 家谱树
拓扑排序模板题,可以边做边输出
#include <bits/stdc++.h>
using namespace std;
const int N=200;
int n,m,deg[N];
vector<int>g[N];
vector<int>ans;
void ts(){
queue<int>q;
for(int i=1;i<=n;i++){
if(deg[i]==0) {q.push(i);cout<<i<<" ";}
}
while(!q.empty()){
int u=q.front();q.pop();
//cout<<u<<'\n';
for(int v:g[u]){
deg[v]--;
if(deg[v]==0){
cout<<v<<" ";
q.push(v);
}
}
}
}
int main(){
cin>>n;
int v;
for(int i=1;i<=n;i++){
while(true){
cin>>v;
if(v==0) break;
g[i].push_back(v);deg[v]++;
}
}
ts();
//for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
return 0;
}
C - A Bug's Life
二分图判定模板题,DFS染色/并查集均可。
#include <iostream>
using namespace std;
const int N=500002;
int father[N],n,m,x,y,z;
int Find(int x) {
return father[x] == x ? x : (father[x] = Find(father[x]));
}
bool Union(int i, int j) {
int x = Find(i);
int y = Find(j);
if (x != y) {
father[x] = y;
return true;
}
return false;
}
void solve(int cas){
cin>>n>>m;
for(int i=1;i<=2*n;i++) father[i]=i;
//bool f=true;
for(int i=1;i<=m;i++){
int u,v;cin>>u>>v;
Union(u+n,v);Union(u,v+n);
}
cout<<"Scenario #"<<cas<<":\n";
for(int i=1;i<=n;i++){
if(Find(i)==Find(i+n)){
cout<<"Suspicious bugs found!\n\n";
return;
}
}
cout<<"No suspicious bugs found!\n\n";
}
int main()
{
//freopen("a.txt","r",stdin);
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int t;cin>>t;
for(int i=1;i<=t;i++){
solve(i);
}
return 0;
}
D - 封锁阳光大学
求二分图较小的一个集合。在并查集做完之后,每一个节点都会指向一个祖先,所以一个祖先就代表了一个块。分别记录块中较小的一部分,累加即可。
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,m;
int father[N];
bool vis[N];
int a[N],b[N];
void Init(int n)
{
for(int i=1;i<=n;i++) father[i]=i;
}
int Find(int x)
{
return father[x]==x?x:(father[x]=Find(father[x]));
}
void Union(int a,int b)
{
int x=Find(a),y=Find(b);
if(x==y) return;
father[x]=y;
}
int main(){
//freopen("a.txt","r",stdin);
cin>>n>>m;
Init(n*2);
for(int i=1;i<=m;i++){
int u,v;cin>>u>>v;a[i]=u,b[i]=v;
int x=Find(u),y=Find(v);
if(x==y){
cout<<"Impossible\n";return 0;
}
Union(u+n,v);Union(u,v+n);
}
int ans=0;
for(int i=1;i<=n;i++){
int x=Find(a[i]),y=Find(b[i]);
if(vis[x]||vis[y]){
continue;
}
vis[x]=vis[y]=true;
int cnt1=0,cnt2=0;
for(int j=1;j<=n;j++){
if(Find(j)==x) cnt1++;
if(Find(j)==y) cnt2++;
}
ans+=min(cnt1,cnt2);
}
cout<<ans<<'\n';
return 0;
}
E - Ping-Pong (Easy Version)
暴力DFS
#include <bits/stdc++.h>
using namespace std;
const int N=1000;
int cnt;
bool vis[N];
struct node{
int l,r;
}a[N];
void dfs(int u){
vis[u]=true;
for(int i=1;i<=cnt;i++){
if(!vis[i]){
if((a[i].l<a[u].l && a[u].l<a[i].r)||(a[i].l<a[u].r&&a[u].r<a[i].r)) dfs(i);
}
}
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
//freopen("a.txt","r",stdin);
int n;cin>>n;
while(n--){
int opt,l,r;
cin>>opt>>l>>r;
if(opt==1){
a[++cnt]={l,r};
}
else{
memset(vis,0,sizeof(vis));
dfs(l);
if(vis[r]) cout<<"YES\n";
else cout<<"NO\n";
}
}
//aaefawef
return 0;
}
F - 最大食物链计数
问题相当于求DAG上有多少条起点入度为0、终点出度为0的路径。拓扑排序中DP即可。
#include <bits/stdc++.h>
using namespace std;
const int N=6000;
const int mod=80112002;
int n,m,ans,deg[N],to[N];
int f[N];
vector<int>g[N];
void ts(){
queue<int>q;
for(int i=1;i<=n;i++){
if(deg[i]==0) {q.push(i);f[i]=1;}
}
while(!q.empty()){
int u=q.front();q.pop();
//cout<<u<<'\n';
for(int v:g[u]){
deg[v]--;f[v]+=f[u];f[v]%=mod;
if(deg[v]==0){
if(to[v]==0) {ans+=f[v];ans%=mod;continue;}
q.push(v);
}
}
}
}
int main(){
//freopen("a.txt","r",stdin);
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v;cin>>u>>v;
g[u].push_back(v);deg[v]++;to[u]++;
}
ts();
cout<<ans<<'\n';
return 0;
}
G - Fox And Names
图论建模。把26个字母看作点,则可以根据给出的字符串,把字典序小的点连向字典序大的边,然后尝试拓扑排序。在输入的时候,对于绝对不合法的情况要特判。
#include <bits/stdc++.h>
using namespace std;
const int N=100000;
int n,tot,deg[N],ans[N];
vector<int>g[N];
string t,s;
int main(){
//freopen("a.txt","r",stdin);
cin>>n>>s;
for(int i=1;i<n;i++){
cin>>t;
int m=min(s.size(),t.size()),j;
for(j=0;j<m;j++){
if(s[j]!=t[j]){
int x=s[j]-96,y=t[j]-96;
g[x].push_back(y);
deg[y]++;
break;
}
}
if(j>=m&&t.size()<s.size()){
printf("Impossible");
return 0;
}
s=t;
}
queue<int>q;
for(int i=1;i<=26;i++) if(!deg[i]) q.push(i);
while(!q.empty()){
int x=q.front();
q.pop();
ans[++tot]=x;
for(auto a:g[x]){
deg[a]--;
if(!deg[a]) q.push(a);
}
}
if(tot<26){
cout<<"Impossible\n";
}
else{
for(int i=1;i<=26;i++) cout<<(char)(ans[i]+'a'-1);
}
return 0;
}
H - Instrction Arrangement
关键路径模板,类似于差分约束,边权取负后SPFA跑最长路即可
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define INF 1e9
using namespace std;
const int maxn =1000+10;
const int maxm =20000+10;
struct Edge
{
int from,to,dist;
Edge(){}
Edge(int f,int t,int d):from(f),to(t),dist(d){}
};
struct BellmanFord
{
int n,m;
int head[maxn],next[maxm];
Edge edges[maxm];
int d[maxn];
bool inq[maxn];
void init(int n)
{
this->n=n;
m=0;
memset(head,-1,sizeof(head));
}
void AddEdge(int from,int to,int dist)
{
edges[m]=Edge(from,to,dist);
next[m]=head[from];
head[from]=m++;
}
void bellmanford()
{
memset(inq,0,sizeof(inq));
for(int i=0;i<n;i++) d[i]= i==0?0:INF;
queue<int> Q;
Q.push(0);
while(!Q.empty())
{
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=head[u];i!=-1;i=next[i])
{
Edge &e=edges[i];
if(d[e.to] > d[u]+e.dist)
{
d[e.to] = d[u]+e.dist;
if(!inq[e.to])
{
inq[e.to]=true;
Q.push(e.to);
}
}
}
}
}
}BF;
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
BF.init(n+1);
while(m--)
{
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
++u,++v;
BF.AddEdge(v,u,-d);
}
for(int i=1;i<=n;i++)
BF.AddEdge(0,i,0);
BF.bellmanford();
int max_v=-1,min_v=INF;
for(int i=1;i<=n;i++)
{
max_v=max(max_v,BF.d[i]);
min_v=min(min_v,BF.d[i]);
}
printf("%d\n",max_v-min_v+1);
}
return 0;
}
I - 寻找道路
建反图,处理出那些点可以走,那些不可以,之后用DFS/BFS/最短路均可
#include<bits/stdc++.h>
using namespace std;
int read()
{
int x=0,y=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='0')y=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*y;
}
int n,m;
vector<int>v[10005];
bool vis[10005],er[10005];
queue<int>q;
int st,ed;
int ans[10005];
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
{
int a=read(),b=read();
if(a==b)continue;
v[b].push_back(a);
}
st=read(),ed=read();
vis[ed]=1;
q.push(ed);
while(!q.empty())
{
int no=q.front();
q.pop();
for(int i=0,j=v[no].size();i<j;i++)
if(!vis[v[no][i]]){vis[v[no][i]]=1;q.push(v[no][i]);}
}
memcpy(er,vis,sizeof(vis));
for(int i=1;i<=n;i++)
if(!vis[i])
for(int j=0,k=v[i].size();j<k;j++)
if(er[v[i][j]])
er[v[i][j]]=0;
q.push(ed);
while(!q.empty())
{
int no=q.front();
q.pop();
for(int i=0,j=v[no].size();i<j;i++)
if(er[v[no][i]])
{
q.push(v[no][i]);
er[v[no][i]]=0;
ans[v[no][i]]=ans[no]+1;
}
}
if(ans[st]==0)cout<<-1<<'\n';
else cout<<ans[st]<<'\n';
return 0;
}