2024.4.9 图论补题
P3225 [HNOI2012] 矿场搭建
如果没有割点,至少需要建立两个出口
如果只有一个割点,只需要设立一个出口
如果有两个及以上个割点,则无需建立,可以直接到达其他联通块
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define maxn 1010
#define INF 0x3f3f3f3f
using namespace std;
int n,tot,Tot,t,cnt,res,js,top,Cnt,Num;
int fr[maxn],to[maxn],Head[maxn],num[maxn],siz[maxn];
int ge[maxn],no[maxn];
bool vis[maxn],flag[maxn],pd[maxn];
int low[maxn],head[maxn],dfn[maxn];
int Dfn[maxn],Low[maxn],Vis[maxn],Zhan[maxn];
struct edge{int fr,to,nxt;}e[maxn<<1];
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
void add(int fr,int to){
e[++tot].to=to;e[tot].fr=fr;
e[tot].nxt=head[fr];head[fr]=tot;
}
void clear(){
tot=js=cnt=t=res=Tot=0;
memset(pd,0,sizeof pd);
memset(dfn,0,sizeof dfn);
memset(low,0,sizeof low);
memset(no,0,sizeof no);
memset(ge,0,sizeof ge);
memset(vis,0,sizeof vis);
memset(head,0,sizeof head);
memset(flag,0,sizeof flag);
memset(Vis,0,sizeof Vis);
memset(siz,0,sizeof siz);
}
void tarjan1(int u,int fat){
dfn[u]=low[u]=++cnt;
vis[u]=1;int chi=0;
for(int i=head[u];i;i=e[i].nxt){
int To=e[i].to;
if(!vis[To]){
chi++;tarjan1(To,u);
low[u]=min(low[u],low[To]);
if(fat!=u&&low[To]>=dfn[u]&&!flag[u]){
flag[u]=1;res++;
}
}
else if(To!=fat) low[u]=min(low[u],dfn[To]);
}
if(fat==u&&chi>=2&&!flag[u]){
flag[u]=1;res++;
}
}
void tarjan2(int u){
Zhan[++top]=u;Vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;
if(!Vis[to]){
tarjan2(to);
if(low[to]>=dfn[u]){
++t;int pre=Zhan[top];
while(pre!=u){
--top;
if(flag[pre]) ++ge[t];
else ++no[t];
pre=Zhan[top];
}
if(flag[pre]) ++ge[t];
else ++no[t];
}
}
}
}
int main(){
while(cin>>n&&n){
clear();
for(int i=1;i<=n;i++){
fr[i]=read();to[i]=read();
add(fr[i],to[i]);add(to[i],fr[i]);
if(!pd[fr[i]]) pd[fr[i]]=1,js++;
if(!pd[to[i]]) pd[to[i]]=1,js++;
}
for(int i=1;i<=js;i++) if(!vis[i]){cnt=0;tarjan1(i,i);}
for(int i=1;i<=js;i++) if(!Vis[i]) tarjan2(i);
long long ans=1;int get=0;
for(int i=1;i<=t;i++){
if(ge[i]>=2) continue;
else if(ge[i]==1){++get;ans*=no[i];}
else if(ge[i]==0){get+=2;ans*=(no[i]*(no[i]-1)/2);}
}
printf("Case %d: %d %lld\n",++Num,get,ans);
}
return 0;
}
CF909E Coprocessor
拓扑排序,让入度为零的点进队,做完主处理器判断副处理器的队列中有无点即可。
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 100010
#define INF 0x3f3f3f3f
//#define int long long
using namespace std;
bool vis[maxn];
int n,m,tot,ans;
int head[maxn],du[maxn];
struct edge{int fr,to,nxt;}e[maxn];
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
void add(int fr,int to){
e[++tot]=(edge){fr,to,head[fr]};head[fr]=tot;
}
void Topsort(){
queue<int> q1,q2;
for(int i=1;i<=n;i++)
if(!du[i]){
if(!vis[i]) q1.push(i);
else q2.push(i);
}
while(!q1.empty()||!q2.empty()){
while(!q1.empty()){
int u=q1.front();q1.pop();
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;du[to]--;
if(!du[to]){
if(!vis[to]) q1.push(to);
else q2.push(to);
}
}
}
ans+=(!q2.empty());
while(!q2.empty()){
int u=q2.front();q2.pop();
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;du[to]--;
if(!du[to]){
if(!vis[to]) q1.push(to);
else q2.push(to);
}
}
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++) vis[i]=read();
for(int i=1,fr,to;i<=m;i++){
fr=read()+1;to=read()+1;
add(fr,to);du[to]++;
}
Topsort();
printf("%d\n",ans);
return 0;
}
P3403 跳楼机
同余最短路模板
\(f_i\) 为通过 2 3 操作到达 \(\text mod x=i\) 楼层的最小楼层
从 \(i\) 向 \(i+y,i+z\) 建立权值为 \(y,z\) 的边。
然后剩下楼层由操作一完成,贡献为 \((h-f_i)/x +1\)
#include<bits/stdc++.h>
#define maxn 200100
#define INF 0x3f3f3f3f
#define int long long
using namespace std;
bool vis[maxn];
int h,x,y,z,tot,ans;
int Dis[maxn],head[maxn];
struct edge{int fr,to,dis,nxt;}e[maxn<<2];
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
void add(int fr,int to,int dis){
e[++tot]=(edge){fr,to,dis,head[fr]};head[fr]=tot;
}
void SPFA(){
memset(Dis,INF,sizeof Dis);
memset(vis,false,sizeof vis);
deque<int> q;q.push_back(1);
Dis[1]=1;vis[1]=true;
while(!q.empty()){
int u=q.front();
q.pop_front();vis[u]=false;
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;
if(Dis[to]>Dis[u]+e[i].dis){
Dis[to]=Dis[u]+e[i].dis;
if(!vis[to]){
vis[to]=1;
if(!q.empty()&&Dis[q.front()]>Dis[to])q.push_front(to);
else q.push_back(to);
}
}
}
}
}
signed main(){
h=read();
x=read();y=read();z=read();
if(x==1||y==1||z==1){cout<<h;return 0;}
for(int i=0;i<x;i++)
add(i,(i+y)%x,y),add(i,(i+z)%x,z);
SPFA();
for(int i=0;i<x;i++)
if(Dis[i]<=h) ans+=(h-Dis[i])/x+1;
printf("%lld\n",ans);
return 0;
}