Loading

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;
}
posted @ 2024-04-09 22:12  KnightL  阅读(10)  评论(0编辑  收藏  举报