文章目录
- 第三讲(二) 图论
- 3.7 负环
- 3.7.1 904. 虫洞
- 3.7.2 361. 观光奶牛
- 3.7.3 1165. 单词环
- 3.8 差分约束
- 3.8.1 1169. 糖果
- 3.8.2 362. 区间
- 3.8.3 1170. 排队布局
- 3.8.4 393. 雇佣收银员
- 3.9 最近公共祖先
- 3.9.1 1172. 祖孙询问
- 3.9.2 1171. 距离
- 3.9.3 356. 次小生成树
- 3.9.4 352. 闇の連鎖
- 3.10 有向图的强连通分量
- 3.10.1 1174. 受欢迎的牛
- 3.10.2 367. 学校网络
- 3.10.3 1175. 最大半连通子图
- 3.10.4 368. 银河
- 3.11 无向图的双连通分量
- 3.11.1 395. 冗余路径
- 3.11.2 1183. 电力
- 3.11.3 396. 矿场搭建
- 3.12 二分图
- 3.12.1 257. 关押罪犯
- 3.12.2 372. 棋盘覆盖
- 3.12.3 376. 机器任务
- 3.12.4 378. 骑士放置
- 3.12.5 379. 捉迷藏
- 3.13 欧拉回路和欧拉路径
- 3.13.1 1123. 铲雪车
- 3.13.2 1184. 欧拉回路
- 3.13.3 1124. 骑马修栅栏
- 3.13.4 1185. 单词游戏
- 3.14 拓扑排序
- 3.14.1 1191. 家谱树
- 3.14.2 1192. 奖金
- 3.14.3 164. 可达性统计
- 3.14.4 456. 车站分级
第三讲(二) 图论
3.7 负环
3.7.1 904. 虫洞
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=6010;
int F,n,m,W;
int h[N],e[M],w[M],ne[M],idx;
int dis[N];
bool st[N];
int cnt[N];
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa()
{
memset(cnt,0,sizeof cnt);
memset(dis,0x3f,sizeof dis);
dis[1]=0;
queue<int> q;
for(int i=1;i<=n;i++)
{
q.push(i);
st[i]=true;
}
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dis[j]>dis[t]+w[i])
{
dis[j]=dis[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n) return true;
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main()
{
ios::sync_with_stdio(0);
cin>>F;
while(F--)
{
memset(h,-1,sizeof h);
idx=0;
cin>>n>>m>>W;
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
for(int i=0;i<W;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,-c);
}
if(spfa()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
3.7.2 361. 观光奶牛
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=5010;
int n,m;
int wf[N];
double dis[N];
bool st[N];
int cnt[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool check(double mid)
{
memset(dis,0,sizeof dis);
memset(st,0,sizeof st);
memset(cnt,0,sizeof cnt);
queue<int> q;
for(int i=1;i<=n;i++)
{
q.push(i);
st[i]=true;
}
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dis[j]<dis[t]+wf[t]-mid*w[i])
{
dis[j]=dis[t]+wf[t]-mid*w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n) return true;
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>wf[i];
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
double l=0,r=1010;
while(r-l>1e-4)
{
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%.2f",r);
return 0;
}
3.7.3 1165. 单词环
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=700,M=100010;
int n;
double dis[N];
bool st[N];
int cnt[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool check(double mid)
{
memset(dis,0,sizeof dis);
memset(st,0,sizeof st);
memset(cnt,0,sizeof cnt);
queue<int> q;
for(int i=0;i<n;i++)
{
q.push(i);
st[i]=true;
}
int sum=0;
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dis[j]<dis[t]+w[i]-mid)
{
dis[j]=dis[t]+w[i]-mid;
cnt[j]=cnt[t]+1;
sum++;
if(cnt[j]>=n) return true;
if(sum>4*n) return true;
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main()
{
while(true)
{
memset(h,-1,sizeof h);
cin>>n;
if(n==0)
break;
for(int i=1;i<=n;i++)
{
string str;
cin>>str;
int len=str.length();
if(len<2) continue;
string left=str.substr(0,2),right=str.substr(len-2);
int a=(left[0]-'a')*26+left[1]-'a',b=(right[0]-'a')*26+right[1]-'a';
add(a,b,len);
}
n=26*26;
if(check(0))
{
double l=0,r=1010;
while(r-l>1e-4)
{
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
printf("%.2f\n",r);
}
else
cout<<"No solution"<<endl;
}
return 0;
}
3.8 差分约束
3.8.1 1169. 糖果
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010,M=300010;
int n,m;
LL dis[N];
int cnt[N];
bool st[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa()
{
memset(dis,-0x3f,sizeof dis);
dis[0]=0;
stack<int> q;
q.push(0);
st[0]=true;
int sum=0;
while(q.size())
{
int t=q.top();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dis[j]<dis[t]+w[i])
{
dis[j]=dis[t]+w[i];
cnt[j]=cnt[t]+1;
sum++;
if(sum>10*n) return false;
if(cnt[j]>=n+1) return false;
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return true;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=0;i<m;i++)
{
int x,a,b;
cin>>x>>a>>b;
if(x==1) add(a,b,0),add(b,a,0);
else if(x==2) add(a,b,1);
else if(x==3) add(b,a,0);
else if(x==4) add(b,a,1);
else add(a,b,0);
}
for(int i=1;i<=n;i++) add(0,i,1);
if(!spfa())
{
cout<<-1<<endl;
}
else
{
LL res=0;
for(int i=1;i<=n;i++)
res+=dis[i];
cout<<res;
}
return 0;
}
3.8.2 362. 区间
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=50010,M=150010;
int n;
int dis[N];
bool st[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void spfa()
{
memset(dis,-0x3f,sizeof dis);
dis[0]=0;
queue<int> q;
q.push(0);
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dis[j]<dis[t]+w[i])
{
dis[j]=dis[t]+w[i];
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
}
int main()
{
memset(h,-1,sizeof h);
cin>>n;
for(int i=1;i<=50001;i++)
{
add(i-1,i,0);
add(i,i-1,-1);
}
for(int i=0;i<n;i++)
{
int a,b,c;
cin>>a>>b>>c;
a++,b++;
add(a-1,b,c);
}
spfa();
cout<<dis[50001];
return 0;
}
3.8.3 1170. 排队布局
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1010,M=30010;
int n,L,D;
int dis[N],cnt[N];
bool st[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool spfa(int x)
{
memset(dis,0x3f,sizeof dis);
memset(st,0,sizeof st);
memset(cnt,0,sizeof cnt);
queue<int> q;
for(int i=1;i<=x;i++)
{
q.push(i);
dis[i]=0;
st[i]=true;
}
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dis[j]>dis[t]+w[i])
{
dis[j]=dis[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=n) return true;
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>L>>D;
for(int i=1;i<n;i++)
add(i+1,i,0);
for(int i=0;i<L;i++)
{
int a,b,c;
cin>>a>>b>>c;
int _min=min(a,b),_max=max(a,b);
add(_min,_max,c);
}
for(int i=0;i<D;i++)
{
int a,b,c;
cin>>a>>b>>c;
int _min=min(a,b),_max=max(a,b);
add(_max,_min,-c);
}
if(spfa(n))
cout<<-1<<endl;
else
{
spfa(1);
if(dis[n]==0x3f3f3f3f) cout<<-2<<endl;
else cout<<dis[n]<<endl;
}
return 0;
}
3.8.4 393. 雇佣收银员
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=30,M=100;
int n;
int dis[N],cnt[N];
int r[N],num[N];
bool st[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void build(int c)
{
memset(h,-1,sizeof h);
idx=0;
for(int i=1;i<=24;i++)
{
add(i-1,i,0);
add(i,i-1,-num[i]);
}
for(int i=1;i<=7;i++) add(i+16,i,r[i]-c);
for(int i=8;i<=24;i++) add(i-8,i,r[i]);
add(0,24,c),add(24,0,-c);
}
bool spfa(int c)
{
build(c);
memset(dis,-0x3f,sizeof dis);
memset(cnt,0,sizeof cnt);
memset(st,0,sizeof st);
queue<int> q;
q.push(0);
dis[0]=0;
st[0]=true;
while(q.size())
{
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(dis[j]<dis[t]+w[i])
{
dis[j]=dis[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>=25) return false;
if(!st[j])
{
q.push(j);
st[j]=true;
}
}
}
}
return true;
}
int main()
{
int T;
cin>>T;
while(T--)
{
for(int i=1;i<=24;i++) cin>>r[i];
cin>>n;
memset(num,0,sizeof num);
for(int i=0;i<n;i++)
{
int t;
cin>>t;
num[t+1]++;
}
bool success=false;
for(int i=0;i<=1000;i++)
{
if(spfa(i))
{
cout<<i<<endl;
success=true;
break;
}
}
if(!success)
cout<<"No Solution"<<endl;
}
return 0;
}
3.9 最近公共祖先
3.9.1 1172. 祖孙询问
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=40010,M=80010;
int n,m;
int fa[N][16],depth[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs(int root)
{
memset(depth,0x3f,sizeof depth);
depth[0]=0,depth[root]=1;
queue<int> q;
q.push(root);
while(q.size())
{
int t=q.front();
q.pop();
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(depth[j]>depth[t]+1)
{
depth[j]=depth[t]+1;
fa[j][0]=t;
q.push(j);
for(int k=1;k<=15;k++)
{
fa[j][k]=fa[fa[j][k-1]][k-1];
}
}
}
}
}
int lca(int a,int b)
{
if(depth[a]<depth[b]) swap(a,b);
for(int k=15;k>=0;k--)
{
if(depth[fa[a][k]]>=depth[b])
a=fa[a][k];
}
if(a==b) return a;
for(int k=0;k<=15;k++)
{
if(fa[a][k]!=fa[b][k])
{
a=fa[a][k];
b=fa[b][k];
}
}
return fa[a][0];
}
int main()
{
memset(h,-1,sizeof h);
cin>>n;
int root;
for(int i=0;i<n;i++)
{
int a,b;
cin>>a>>b;
if(b==-1) root=a;
else
{
add(a,b),add(b,a);
}
}
bfs(root);
cin>>m;
while(m--)
{
int a,b;
cin>>a>>b;
int p=lca(a,b);
if(p==a) cout<<1<<endl;
else if(p==b) cout<<2<<endl;
else cout<<0<<endl;
}
return 0;
}
3.9.2 1171. 距离
代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;//first保存相关的查询节点编号,second保存查询编号
const int N=10010,M=20010;
int n,m;
int dis[N];
int p[N];
int res[M];
int st[N];
vector<PII> query[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int findP(int x)
{
if(p[x]!=x) return p[x]=findP(p[x]);
return p[x];
}
void dfs(int u,int fa)
{
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
dis[j]=dis[u]+w[i];
dfs(j,u);
}
}
void tarjan(int u)
{
st[u]=1;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!st[j])
{
tarjan(j);
p[j]=u;
}
}
for(int i=0;i<query[u].size();i++)
{
PII t=query[u][i];
int y=t.first,id=t.second;
if(st[y]==2)
{
int anc=findP(y);
res[id]=dis[u]+dis[y]-2*dis[anc];
}
}
st[u]=2;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
for(int i=0;i<n-1;i++)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
if(a!=b)
{
query[a].push_back(make_pair(b,i));
query[b].push_back(make_pair(a,i));
}
}
for(int i=1;i<=n;i++) p[i]=i;
dfs(1,-1);
tarjan(1);
for(int i=0;i<m;i++)
{
cout<<res[i]<<endl;
}
return 0;
}
3.9.3 356. 次小生成树
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010,M=300010,INF=0x3f3f3f3f;
int n,m;
int p[N];
int depth[N],fa[N][17],d1[N][17],d2[N][17];
int q[N];
struct Edge{
int a,b,w;
bool used;
bool operator < (const Edge &t) const
{
return w<t.w;
}
}edge[M];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int findP(int x)
{
if(p[x]!=x) return p[x]=findP(p[x]);
return p[x];
}
LL kruskal()
{
for(int i=1;i<=n;i++) p[i]=i;
sort(edge,edge+m);
LL res=0;
for(int i=0;i<m;i++)
{
int a=findP(edge[i].a),b=findP(edge[i].b),w=edge[i].w;
if(a!=b)
{
p[a]=b;
res+=w;
edge[i].used=true;
}
}
return res;
}
void build()
{
memset(h,-1,sizeof h);
for(int i=0;i<m;i++)
{
if(edge[i].used)
{
int a=edge[i].a,b=edge[i].b,w=edge[i].w;
add(a,b,w),add(b,a,w);
}
}
}
void bfs()
{
memset(depth,0x3f,sizeof depth);
depth[0]=0,depth[1]=1;
queue<int> q;
q.push(1);
while(q.size())
{
int t=q.front();
q.pop();
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(depth[j]>depth[t]+1)
{
depth[j]=depth[t]+1;
q.push(j);
fa[j][0]=t;
d1[j][0]=w[i],d2[j][0]=-INF;
for(int k=1;k<=16;k++)
{
int anc=fa[j][k-1];
fa[j][k]=fa[anc][k-1];
int distance[4]={d1[j][k-1],d2[j][k-1],d1[anc][k-1],d2[anc][k-1]};
d1[j][k]=d2[j][k]=-INF;
for(int u=0;u<4;u++)
{
int d=distance[u];
if(d>d1[j][k]) d2[j][k]=d1[j][k],d1[j][k]=d;
else if(d!=d1[j][k]&&d>d2[j][k]) d2[j][k]=d;
}
}
}
}
}
}
int lca(int a,int b,int w)
{
static int distance[2*N];
int cnt=0;
if(depth[a]<depth[b]) swap(a,b);
for(int k=16;k>=0;k--)
{
if(depth[fa[a][k]]>=depth[b])
{
distance[cnt++]=d1[a][k];
distance[cnt++]=d2[a][k];
a=fa[a][k];
}
}
if(a!=b)
{
for(int k=16;k>=0;k--)
{
if(fa[a][k]!=fa[b][k])
{
distance[cnt++]=d1[a][k];
distance[cnt++]=d2[a][k];
distance[cnt++]=d1[b][k];
distance[cnt++]=d2[b][k];
a=fa[a][k],b=fa[b][k];
}
}
distance[cnt++]=d1[a][0];
distance[cnt++]=d1[b][0];
}
int dist1=-INF,dist2=-INF;
for(int i=0;i<cnt;i++)
{
int d=distance[i];
if(d>dist1) dist2=dist1,dist1=d;
else if(d!=dist1&&d>dist2) dist2=d;
}
if(w>dist1) return w-dist1;
if(w>dist2) return w-dist2;
return INF;
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
edge[i].a=a,edge[i].b=b,edge[i].w=c;
}
LL sum=kruskal();
build();
bfs();
LL res=1e18;
for(int i=0;i<m;i++)
{
if(!edge[i].used)
{
int a=edge[i].a,b=edge[i].b,w=edge[i].w;
res=min(res,sum+lca(a,b,w));
}
}
cout<<res;
return 0;
}
3.9.4 352. 闇の連鎖
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=200010;
int n,m;
int depth[N],fa[N][17];
int d[N];
int ans;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs()
{
memset(depth,0x3f,sizeof depth);
depth[0]=0,depth[1]=1;
queue<int> q;
q.push(1);
while(q.size())
{
int t=q.front();
q.pop();
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(depth[j]>depth[t]+1)
{
depth[j]=depth[t]+1;
q.push(j);
fa[j][0]=t;
for(int k=1;k<=16;k++)
{
fa[j][k]=fa[fa[j][k-1]][k-1];
}
}
}
}
}
int lca(int a,int b)
{
if(depth[a]<depth[b]) swap(a,b);
for(int k=16;k>=0;k--)
{
if(depth[fa[a][k]]>=depth[b])
a=fa[a][k];
}
if(a==b) return a;
for(int k=16;k>=0;k--)
{
if(fa[a][k]!=fa[b][k])
{
a=fa[a][k];
b=fa[b][k];
}
}
return fa[a][0];
}
int dfs(int u,int father)
{
int res=d[u];
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(j!=father)
{
int s=dfs(j,u);
if(s==0) ans+=m;
else if(s==1) ans++;
res+=s;
}
}
return res;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
for(int i=0;i<n-1;i++)
{
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
bfs();
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
int p=lca(a,b);
d[a]+=1,d[b]+=1,d[p]-=2;
}
dfs(1,-1);
cout<<ans;
return 0;
}
3.10 有向图的强连通分量
3.10.1 1174. 受欢迎的牛
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=10010,M=50010;
int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
bool in_stk[N];
int id[N],scc_cnt,sz[N];
int dout[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++timestamp;
stk.push(u),in_stk[u]=true;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],low[j]);
}
else if(in_stk[j])
low[u]=min(low[u],dfn[j]);
}
if(dfn[u]==low[u])
{
++scc_cnt;
int y;
do{
y=stk.top();
stk.pop();
in_stk[y]=false;
id[y]=scc_cnt;
sz[scc_cnt]++;
}while(y!=u);
}
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
while(m--)
{
int a,b;
cin>>a>>b;
add(a,b);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
for(int i=1;i<=n;i++)
{
for(int j=h[i];j!=-1;j=ne[j])
{
int k=e[j];
int a=id[i],b=id[k];
if(a!=b) dout[a]++;
}
}
int zeros=0,sum=0;
for(int i=1;i<=scc_cnt;i++)
{
if(!dout[i])
{
zeros++;
sum+=sz[i];
if(zeros>1)
{
sum=0;
break;
}
}
}
cout<<sum;
return 0;
}
3.10.2 367. 学校网络
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=110,M=10010;
int n;
int dfn[N],low[N],timestamp;
stack<int> stk;
bool in_stk[N];
int id[N],scc_cnt,sz[N];
int din[N],dout[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++timestamp;
stk.push(u),in_stk[u]=true;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],low[j]);
}
else if(in_stk[j]) low[u]=min(low[u],dfn[j]);
}
if(dfn[u]==low[u])
{
++scc_cnt;
int y;
do{
y=stk.top();
stk.pop();
in_stk[y]=false;
id[y]=scc_cnt;
sz[scc_cnt]++;
}while(y!=u);
}
}
int main()
{
memset(h,-1,sizeof h);
cin>>n;
for(int i=1;i<=n;i++)
{
while(true)
{
int b;
cin>>b;
if(b==0) break;
add(i,b);
}
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
for(int i=1;i<=n;i++)
{
for(int j=h[i];j!=-1;j=ne[j])
{
int k=e[j];
int a=id[i],b=id[k];
if(a!=b) din[b]++,dout[a]++;
}
}
int p=0,q=0;
for(int i=1;i<=scc_cnt;i++)
{
if(!din[i]) p++;
if(!dout[i]) q++;
}
cout<<p<<endl;
if(scc_cnt==1)
cout<<0<<endl;
else
cout<<max(p,q)<<endl;
return 0;
}
3.10.3 1175. 最大半连通子图
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010,M=2000010;
int n,m,mod;
int dfn[N],low[N],timestamp;
stack<int> stk;
bool in_stk[N];
int id[N],scc_cnt,sz[N];
int f[N],g[N];
int h[N],hs[N],e[M],ne[M],idx;
void add(int h[],int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++timestamp;
stk.push(u),in_stk[u]=true;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],low[j]);
}
else if(in_stk[j]) low[u]=min(low[u],dfn[j]);
}
if(dfn[u]==low[u])
{
++scc_cnt;
int y;
do{
y=stk.top();
stk.pop();
in_stk[y]=false;
id[y]=scc_cnt;
sz[scc_cnt]++;
}while(y!=u);
}
}
int main()
{
memset(h,-1,sizeof h);
memset(hs,-1,sizeof hs);
cin>>n>>m>>mod;
while(m--)
{
int a,b;
cin>>a>>b;
add(h,a,b);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
unordered_set<LL> S;
for(int i=1;i<=n;i++)
{
for(int j=h[i];j!=-1;j=ne[j])
{
int k=e[j];
int a=id[i],b=id[k];
LL ha=a*1000000ll+b;
if(a!=b&&!S.count(ha))
{
add(hs,a,b);
S.insert(ha);
}
}
}
for(int i=scc_cnt;i>0;i--)
{
if(!f[i])
{
f[i]=sz[i];
g[i]=1;
}
for(int j=hs[i];j!=-1;j=ne[j])
{
int k=e[j];
if(f[k]<f[i]+sz[k])
{
f[k]=f[i]+sz[k];
g[k]=g[i];
}
else if(f[k]==f[i]+sz[k])
g[k]=(g[k]+g[i])%mod;
}
}
int maxf=0,sum=0;
for(int i=1;i<=scc_cnt;i++)
{
if(f[i]>maxf)
{
maxf=f[i];
sum=g[i];
}
else if(f[i]==maxf) sum=(sum+g[i])%mod;
}
cout<<maxf<<endl;
cout<<sum<<endl;
return 0;
}
3.10.4 368. 银河
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010,M=600010;
int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
bool in_stk[N];
int id[N],scc_cnt,sz[N];
int dis[N];
int h[N],hs[N],e[M],w[M],ne[M],idx;
void add(int h[],int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++timestamp;
stk.push(u),in_stk[u]=true;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],dfn[j]);
}
else if(in_stk[j]) low[u]=min(low[u],dfn[j]);
}
if(dfn[u]==low[u])
{
++scc_cnt;
int y;
do{
y=stk.top();
stk.pop();
in_stk[y]=false;
id[y]=scc_cnt;
sz[scc_cnt]++;
}while(y!=u);
}
}
int main()
{
memset(h,-1,sizeof h);
memset(hs,-1,sizeof hs);
cin>>n>>m;
for(int i=1;i<=n;i++)
add(h,0,i,1);
while(m--)
{
int t,a,b;
cin>>t>>a>>b;
if(t==1) add(h,b,a,0),add(h,a,b,0);
else if(t==2) add(h,a,b,1);
else if(t==3) add(h,b,a,0);
else if(t==4) add(h,b,a,1);
else add(h,a,b,0);
}
tarjan(0);
bool success=true;
for(int i=0;i<=n;i++)
{
for(int j=h[i];j!=-1;j=ne[j])
{
int k=e[j];
int a=id[i],b=id[k];
if(a==b)
{
if(w[j]>0)
{
success=false;
break;
}
}
else add(hs,a,b,w[j]);
}
if(!success) break;
}
if(!success) cout<<-1<<endl;
else
{
for(int i=scc_cnt;i>0;i--)
{
for(int j=hs[i];j!=-1;j=ne[j])
{
int k=e[j];
dis[k]=max(dis[k],dis[i]+w[j]);
}
}
LL res=0;
for(int i=1;i<=scc_cnt;i++) res+=(LL)dis[i]*sz[i];
cout<<res;
}
return 0;
}
3.11 无向图的双连通分量
3.11.1 395. 冗余路径
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5010,M=20010;
int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
int id[N],dcc_cnt;
bool is_bridge[M];
int d[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u,int from)
{
dfn[u]=low[u]=++timestamp;
stk.push(u);
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j,i);
low[u]=min(low[u],low[j]);
if(dfn[u]<low[j])
{
is_bridge[i]=is_bridge[i^1]=true;
}
}
else if(i!=(from^1))
low[u]=min(low[u],dfn[j]);
}
if(dfn[u]==low[u])
{
++dcc_cnt;
int y;
do{
y=stk.top();
stk.pop();
id[y]=dcc_cnt;
}while(y!=u);
}
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
while(m--)
{
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
tarjan(1,-1);
for(int i=0;i<idx;i++)
{
if(is_bridge[i])
d[id[e[i]]]++;
}
int cnt=0;
for(int i=1;i<=dcc_cnt;i++)
if(d[i]==1)
cnt++;
cout<<(cnt+1)/2;
return 0;
}
3.11.2 1183. 电力
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=300010;
int n,m;
int dfn[N],low[N],timestamp;
int root,ans;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++timestamp;
int cnt=0;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],low[j]);
if(low[j]>=dfn[u]) cnt++;
}
else low[u]=min(low[u],dfn[j]);
}
if(u!=root) cnt++;
ans=max(ans,cnt);
}
int main()
{
while(true)
{
cin>>n>>m;
if(n==0&&m==0) break;
memset(h,-1,sizeof h);
memset(dfn,0,sizeof dfn);
idx=timestamp=0;
while(m--)
{
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
ans=0;
int cnt=0;
for(root=0;root<n;root++)
{
if(!dfn[root])
{
cnt++;
tarjan(root);
}
}
cout<<ans+cnt-1<<endl;
}
return 0;
}
3.11.3 396. 矿场搭建
代码:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N=1010,M=1010;
int n,m;
int dfn[N],low[N],timestamp;
stack<int> stk;
int dcc_cnt;
vector<int> dcc[N];
bool cut[N];
int root;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++timestamp;
stk.push(u);
if(u==root&&h[u]==-1)
{
dcc_cnt++;
dcc[dcc_cnt].push_back(u);
return;
}
int cnt=0;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],low[j]);
if(dfn[u]<=low[j])
{
cnt++;
if(u!=root||cnt>1) cut[u]=true;
++dcc_cnt;
int y;
do{
y=stk.top();
stk.pop();
dcc[dcc_cnt].push_back(y);
}while(y!=j);
dcc[dcc_cnt].push_back(u);
}
}
else low[u]=min(low[u],dfn[j]);
}
}
int main()
{
int T=1;
while(true)
{
cin>>m;
if(m==0) break;
memset(h,-1,sizeof h);
memset(dfn,0,sizeof dfn);
memset(cut,0,sizeof cut);
for(int i=0;i<N;i++) dcc[i].clear();
idx=n=timestamp=dcc_cnt=0;
while(m--)
{
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
n=max(n,a);
n=max(n,b);
}
for(root=1;root<=n;root++)
{
if(!dfn[root])
tarjan(root);
}
int res=0;
ULL num=1;
for(int i=1;i<=dcc_cnt;i++)
{
int cnt=0;
for(int j=0;j<dcc[i].size();j++)
{
if(cut[dcc[i][j]])
cnt++;
}
if(cnt==0)
{
if(dcc[i].size()>1) res+=2,num*=dcc[i].size()*(dcc[i].size()-1)/2;
else res++;
}
else if(cnt==1) res++,num*=dcc[i].size()-1;
}
cout<<"Case "<<T<<": "<<res<<" "<<num<<endl;
T++;
}
return 0;
}
3.12 二分图
3.12.1 257. 关押罪犯
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=20010,M=200010;
int n,m;
int color[N]; //0表示未染色,1表示染白色,2表示染黑色
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool dfs(int u,int c,int mid)
{
color[u]=c;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(w[i]<=mid) continue;
if(color[j])
{
if(color[j]==c) return false;
}
else if(!dfs(j,3-c,mid)) return false;
}
return true;
}
bool check(int mid)
{
memset(color,0,sizeof color);
for(int i=1;i<=n;i++)
{
if(!color[i])
{
if(!dfs(i,1,mid))
return false;
}
}
return true;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
int l=0,r=1e9;
while(l<r)
{
int mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<r;
return 0;
}
3.12.2 372. 棋盘覆盖
代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=110;
int n,t;
PII match[N][N];
int g[N][N];
bool st[N][N];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
bool findG(int x,int y)
{
for(int i=0;i<4;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<1||a>n||b<1||b>n) continue;
if(st[a][b]||g[a][b]) continue;
st[a][b]=true;
PII t=match[a][b];
if(t.first==-1||findG(t.first,t.second))
{
match[a][b]=make_pair(x,y);
return true;
}
}
return false;
}
int main()
{
cin>>n>>t;
while(t--)
{
int x,y;
cin>>x>>y;
g[x][y]=true;
}
memset(match,-1,sizeof match);
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((i+j)%2&&!g[i][j])
{
memset(st,0,sizeof st);
if(findG(i,j)) res++;
}
}
}
cout<<res;
return 0;
}
3.12.3 376. 机器任务
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int n,m,k;
int match[N];
bool g[N][N],st[N];
bool findG(int x)
{
for(int i=1;i<m;i++)
{
if(!st[i]&&g[x][i])
{
st[i]=true;
if(match[i]==-1||findG(match[i]))
{
match[i]=x;
return true;
}
}
}
return false;
}
int main()
{
while(true)
{
cin>>n;
if(n==0) break;
cin>>m>>k;
memset(g,0,sizeof g);
memset(match,-1,sizeof match);
while(k--)
{
int t,a,b;
cin>>t>>a>>b;
if(!a||!b) continue;
g[a][b]=true;
}
int res=0;
for(int i=1;i<n;i++)
{
memset(st,0,sizeof st);
if(findG(i)) res++;
}
cout<<res<<endl;
}
return 0;
}
3.12.4 378. 骑士放置
代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=110;
int n,m,t;
int g[N][N];
PII match[N][N];
bool st[N][N];
int dx[8]={-2,-1,1,2,2,1,-1,-2},dy[8]={1,2,2,1,-1,-2,-2,-1};
bool findG(int x,int y)
{
for(int i=0;i<8;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<1||a>n||b<1||b>m) continue;
if(st[a][b]||g[a][b]) continue;
st[a][b]=true;
PII t=match[a][b];
if(t.first==-1||findG(t.first,t.second))
{
match[a][b]=make_pair(x,y);
return true;
}
}
return false;
}
int main()
{
cin>>n>>m>>t;
for(int i=0;i<t;i++)
{
int x,y;
cin>>x>>y;
g[x][y]=true;
}
memset(match,-1,sizeof match);
int res=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if((i+j)%2&&!g[i][j])
{
memset(st,0,sizeof st);
if(findG(i,j)) res++;
}
}
}
cout<<n*m-res-t;
return 0;
}
3.12.5 379. 捉迷藏
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=210;
int n,m;
int match[N];
bool st[N],d[N][N];
bool findG(int x)
{
for(int i=1;i<=n;i++)
{
if(d[x][i]&&!st[i])
{
st[i]=true;
int t=match[i];
if(t==0||findG(t))
{
match[i]=x;
return true;
}
}
}
return false;
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
d[a][b]=true;
}
//求传递闭包
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]|=d[i][k]&d[k][j];
int res=0;
for(int i=1;i<=n;i++)
{
memset(st,0,sizeof st);
if(findG(i)) res++;
}
cout<<n-res;
return 0;
}
3.13 欧拉回路和欧拉路径
3.13.1 1123. 铲雪车
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
double x1,y1,x2,y2;
cin>>x1>>y1;
double sum=0;
while(cin>>x1>>y1>>x2>>y2)
{
double dx=x1-x2;
double dy=y1-y2;
sum+=sqrt(dx*dx+dy*dy)*2;
}
int minutes=round(sum/1000/20*60);
int hours=minutes/60;
minutes%=60;
printf("%d:%02d\n",hours,minutes);
return 0;
}
3.13.2 1184. 欧拉回路
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=100010,M=400010;
int type;
int n,m;
int ans[M],cnt;
int din[N],dout[N];
int h[N],e[M],ne[M],idx;
bool used[M];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u)
{
for(int &i=h[u];i!=-1;)
{
if(used[i])
{
i=ne[i];
continue;
}
used[i]=true;
if(type==1) used[i^1]=true;
int t;
if(type==1)
{
t=i/2+1;
if(i&1) t=-t;
}
else t=i+1;
int j=e[i];
i=ne[i];
dfs(j);
ans[++cnt]=t;
}
}
int main()
{
memset(h,-1,sizeof h);
cin>>type;
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
add(a,b);
if(type==1) add(b,a);
din[b]++,dout[a]++;
}
if(type==1)
{
for(int i=1;i<=n;i++)
{
if(din[i]+dout[i]&1)
{
cout<<"NO"<<endl;
return 0;
}
}
}
else
{
for(int i=1;i<=n;i++)
{
if(din[i]!=dout[i])
{
cout<<"NO"<<endl;
return 0;
}
}
}
for(int i=1;i<=n;i++)
{
if(h[i]!=-1)
{
dfs(i);
break;
}
}
if(cnt<m)
{
cout<<"NO"<<endl;
return 0;
}
cout<<"YES"<<endl;
for(int i=cnt;i>0;i--) cout<<ans[i]<<" ";
return 0;
}
3.13.3 1124. 骑马修栅栏
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=1100;
int n=500,m;
int g[N][N];
int ans[M],cnt;
int d[N];
void dfs(int u)
{
for(int i=1;i<=n;i++)
{
if(g[u][i])
{
g[u][i]--,g[i][u]--;
dfs(i);
}
}
ans[++cnt]=u;
}
int main()
{
cin>>m;
while(m--)
{
int a,b;
cin>>a>>b;
g[a][b]++,g[b][a]++;
d[a]++,d[b]++;
}
int start=1;
while(!d[start]) start++;
for(int i=1;i<=n;i++)
{
if(d[i]%2)
{
start=i;
break;
}
}
dfs(start);
for(int i=cnt;i>0;i--) cout<<ans[i]<<endl;
return 0;
}
3.13.4 1185. 单词游戏
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=30;
int t,n;
int din[N],dout[N];
int p[N];
bool st[N];
int findP(int x)
{
if(p[x]!=x) return p[x]=findP(p[x]);
return p[x];
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
memset(din,0,sizeof din);
memset(dout,0,sizeof dout);
memset(st,0,sizeof st);
for(int i=0;i<26;i++) p[i]=i;
string str;
for(int i=0;i<n;i++)
{
cin>>str;
int a=str[0]-'a',b=str[str.length()-1]-'a';
dout[a]++,din[b]++;
st[a]=true,st[b]=true;
p[findP(a)]=findP(b);
}
bool flag1=true,flag2=true;
int start=0,ed=0;
for(int i=0;i<26;i++)
{
if(din[i]!=dout[i])
{
flag1=false;
if(din[i]-dout[i]==1)
ed++;
else if(dout[i]-din[i]==1)
start++;
else
{
flag2=false;
break;
}
}
}
int t=findP(0);
for(int i=1;i<26;i++)
{
if(st[i]&&findP(i)!=t)
{
flag1=false;
break;
}
}
if(flag1||flag2&&start==1&&ed==1)
cout<<"Ordering is possible."<<endl;
else
cout<<"The door cannot be opened."<<endl;
}
return 0;
}
3.14 拓扑排序
3.14.1 1191. 家谱树
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=110,M=10010;
int n;
int d[N];
vector<int> ans;
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void topsort()
{
queue<int> q;
for(int i=1;i<=n;i++)
{
if(d[i]==0) q.push(i);
}
while(q.size())
{
int t=q.front();
q.pop();
ans.push_back(t);
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
d[j]--;
if(d[j]==0) q.push(j);
}
}
}
int main()
{
memset(h,-1,sizeof h);
cin>>n;
for(int i=1;i<=n;i++)
{
while(true)
{
int x;
cin>>x;
if(x==0) break;
add(i,x);
d[x]++;
}
}
topsort();
for(int i=0;i<ans.size();i++)
{
cout<<ans[i]<<" ";
}
return 0;
}
3.14.2 1192. 奖金
代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int N=10010,M=20010;
int n,m;
int d[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int topsort()
{
int res=0,cnt=0;
queue<PII> q;
for(int i=1;i<=n;i++)
{
if(d[i]==0)
{
q.push(make_pair(i,100));
res+=100;
cnt++;
}
}
while(q.size())
{
PII t=q.front();
q.pop();
for(int i=h[t.first];i!=-1;i=ne[i])
{
int j=e[i];
d[j]--;
if(d[j]==0)
{
res+=t.second+1;
q.push(make_pair(j,t.second+1));
cnt++;
}
}
}
if(cnt<n) return -1;
return res;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
add(b,a);
d[a]++;
}
int t=topsort();
if(t==-1) cout<<"Poor Xed"<<endl;
else cout<<t<<endl;
return 0;
}
3.14.3 164. 可达性统计
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=30010;
int n,m;
int d[N];
vector<int> seq;
bitset<N> f[N];
int h[N],e[N],ne[N],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void topsort()
{
queue<int> q;
for(int i=1;i<=n;i++)
{
if(d[i]==0)
{
q.push(i);
seq.push_back(i);
}
}
while(q.size())
{
int t=q.front();
q.pop();
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
d[j]--;
if(d[j]==0)
{
q.push(j);
seq.push_back(j);
}
}
}
}
int main()
{
ios::sync_with_stdio(0);
memset(h,-1,sizeof h);
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
add(a,b);
d[b]++;
}
topsort();
for(int i=n-1;i>=0;i--)
{
int j=seq[i];
f[j][j]=1;
for(int k=h[j];k!=-1;k=ne[k])
f[j]|=f[e[k]];
}
for(int i=1;i<=n;i++) cout<<f[i].count()<<endl;
return 0;
}
3.14.4 456. 车站分级
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2010,M=1000010;
int n,m;
int d[N];
bool stop[N];
vector<int> seq;
int dis[N];
int h[N],e[M],w[M],ne[M],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void topsort()
{
queue<int> q;
for(int i=1;i<=n+m;i++)
{
if(d[i]==0)
{
q.push(i);
seq.push_back(i);
}
}
while(q.size())
{
int t=q.front();
q.pop();
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
d[j]--;
if(d[j]==0)
{
q.push(j);
seq.push_back(j);
}
}
}
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int s;
cin>>s;
int start,ed;
memset(stop,0,sizeof stop);
for(int j=0;j<s;j++)
{
int x;
cin>>x;
if(j==0) start=x;
if(j==s-1) ed=x;
stop[x]=true;
}
int vir=n+i;
for(int j=start;j<=ed;j++)
{
if(stop[j])
{
add(vir,j,1);
d[j]++;
}
else
{
add(j,vir,0);
d[vir]++;
}
}
}
topsort();
for(int i=1;i<=n;i++) dis[i]=1;
for(int i=0;i<seq.size();i++)
{
int t=seq[i];
for(int j=h[t];j!=-1;j=ne[j])
{
int k=e[j];
dis[k]=max(dis[k],dis[t]+w[j]);
}
}
set<int> eq;
for(int i=1;i<=n;i++)
eq.insert(dis[i]);
cout<<eq.size();
return 0;
}