ACM图论模版.docx
《ACM图论模版.docx》由会员分享,可在线阅读,更多相关《ACM图论模版.docx(22页珍藏版)》请在冰豆网上搜索。
![ACM图论模版.docx](https://file1.bdocx.com/fileroot1/2023-1/7/7418bd79-ee91-4525-8a02-1fae86bd13e5/7418bd79-ee91-4525-8a02-1fae86bd13e51.gif)
ACM图论模版
图论
网络流模版
#include
#include
#include
usingnamespacestd;
#defineM220
#defineINF20000000
structnode{
intfrom,to,dis;
intnest;
}qe[M*100];
inthand[M],que[M],sta[M];
intn,m,len;
intdis[M];
voidab(intu,intv,intw){
qe[len].from=u;qe[len].to=v;
qe[len].dis=w;qe[len].nest=hand[u];hand[u]=len++;
qe[len].from=v;qe[len].to=u;
qe[len].dis=0;qe[len].nest=hand[v];hand[v]=len++;
}
intdinic(intst,intet){
intans=0;
intfront,tail;
intu,v,i;
while
(1){
front=tail=0;
memset(dis,-1,sizeof(dis));
que[tail++]=st;dis[st]=0;
while(frontintx=que[front++];
for(inti=hand[x];i!
=-1;i=qe[i].nest){
intu=qe[i].to;
if(dis[u]==-1&&qe[i].dis>0){
dis[u]=dis[x]+1;
que[tail++]=u;
if(u==et){
front=tail;
break;
}
}
}
}
if(dis[et]==-1)break;
intt=0;
ints=st;
while
(1){
if(s!
=et){
inti;
for(i=hand[s];i!
=-1;i=qe[i].nest)
if(qe[i].dis>0&&dis[qe[i].to]==dis[qe[i].from]+1)
break;
if(i!
=-1){
sta[t++]=i;
s=qe[i].to;
}
else{
if(t==0){
break;
}
dis[qe[sta[--t]].to]=-1;
s=qe[sta[t]].from;
}
}
else{
intmin=INF;
intnow;
for(inti=0;iif(min>qe[sta[i]].dis){
min=qe[sta[i]].dis;
now=i;
}
ans+=min;
for(inti=0;iqe[sta[i]].dis-=min;
qe[sta[i]^1].dis+=min;
}
s=qe[sta[now]].from;
t=now;
}
}
}
returnans;
}
intmain()
{
inti,j,u,v,w;
while(scanf("%d%d",&n,&m)!
=EOF){
memset(hand,-1,sizeof(hand));
len=0;
for(i=0;iscanf("%d%d%d",&u,&v,&w);
ab(u,v,w);
}
cout<}
}
差分约束
//用SPFA解差分方程,用最短路径求差分方程的最大解;用最长路径求差分方程的最小解.
#include
#include
#include
#include
#include
#definemaxn50010
#defineINF20000000
usingnamespacestd;
//d[t+1]-d[s]>=c,也就是dist[t+1]>=dist[s]+c,
//dis[e]-dis[s]>=c也就是dis[e]-dis[s]//也就是最长路松弛技术
//这是求最长路的形式,所以要求最长路//看形势
structnode
{
intto,next,val;
}edge[maxn*3];
inthead[maxn],top,d[maxn];
boolvi[maxn];
voidUnit(intu,intv,intval)
{
edge[top].next=head[u];edge[top].to=v;
edge[top].val=val;head[u]=top++;
}
voidspfa(intMin,intMax)
{
inti,j,now;
intu,w;
memset(vi,0,sizeof(vi));
queueq;
for(i=Min;i<=Max;i++)
d[i]=-INF;//因为求最长路
d[Min]=0;
q.push(Min);
vi[Min]=1;
while(!
q.empty())
{
now=q.front();
q.pop();
//cout<for(i=head[now];i!
=-1;i=edge[i].next)
{
u=edge[i].to;
w=edge[i].val;
if(d[u]{
d[u]=w+d[now];
if(!
vi[u])
{
q.push(u);
vi[u]=1;
}
}
}
vi[now]=0;
}
}
intmain()
{
inti,n,m,j;
intMin,Max,u,v,w;
//freopen("in.txt","r",stdin);
while(scanf("%d",&n)!
=EOF)
{
Max=0;Min=INF;
top=0;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&u,&v,&w);
Unit(u,v+1,w);
if(v+1>Max)
Max=v+1;
if(u}
for(i=Min;i{
Unit(i+1,i,-1);
Unit(i,i+1,0);
}
spfa(Min,Max);
cout<}
return0;
}
次小最短路和方法数
#defineINF100000002
typedefpairpii;
vectorqe[MAXN];
voiddfs(intn,ints,inte)
{
inti,min,j,u,w,k;
intnow,v;
memset(vi,0,sizeof(vi));
memset(mun,0,sizeof(mun));
for(i=1;i<=n;i++)
{
d[i][0]=INF;
d[i][1]=INF;
}
d[s][0]=0;
mun[s][0]=1;
for(j=1;j<2*n;j++)//因为是求两者所以2*n-1次
{
min=INF;
for(i=1;i<=n;i++)
if(!
vi[i][0]&&d[i][0]{
min=d[i][0];
now=0;
k=i;
}//也可以使次短路出队
elseif(!
vi[i][1]&&d[i][1]{
min=d[i][1];
now=1;
k=i;
}
if(min==INF)break;
vi[k][now]=1;
for(i=0;i{
u=qe[k][i].first;
w=qe[k][i].second;
//最短的被更新了】
//所以这个节点次短就成为原来自己
if(d[u][0]>min+w)
{
d[u][1]=d[u][0];
mun[u][1]=mun[u][0];
//注意更新次序
d[u][0]=min+w;
mun[u][0]=mun[k][now];
}
elseif(d[u][0]==min+w)
mun[u][0]+=mun[k][now];
//如果大于次短路则更新
elseif(d[u][1]>min+w)
{
d[u][1]=min+w;
mun[u][1]=mun[k][now];
}
elseif(d[u][1]==min+w)
mun[u][1]+=mun[k][now];
}
}
}
intmain()
{
inti,j,n,m,T;
intu,v,w,s,e;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
qe[i].clear();
while(m--)
{//竟然是有向图!
!
scanf("%d%d%d",&u,&v,&w);
qe[u].push_back(make_pair(v,w));
}
scanf("%d%d",&s,&e);
dfs(n,s,e);
//如果次短比最短多一则把它加上
if(d[e][0]+1==d[e][1])
mun[e][0]+=mun[e][1];
printf("%d\n",mun[e][0]);
}
}
边双联通
voiddfs(intu,intfa)
{
intv,i,k;
pre[u]=low[u]=++dfs_time;
for(i=head[u];i!
=-1;i=next1[i])
{
v=to[i];
if(!
pre[v])
{
dfs(v,u);
low[u]=min(low[u],low[v]);
}
elseif(pre[v]
=fa)
{
low[u]=min(low[u],pre[v]);
}
}
}
voiddfs1(intu)
{
inti,v;
vi[u]=1;
for(i=head[u];i!
=-1;i=next1[i])
{
v=to[i];
if(low[v]!
=low[u])
{
in[low[u]]++;
}
if(vi[v])continue;
dfs1(v);
}
}
voidUnit(intu,intv)
{
next1[top]=head[u];to[top]=v;
head[u]=top++;
next1[top]=head[v];to[top]=u;
head[v]=top++;
}
intmain()
{
inti,n,m,j,k,case1=0;
intu,v,ans;
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)!
=EOF)
{
memset(head,-1,sizeof(head));
memset(pre,0,sizeof(pre));
memset(in,0,sizeof(in));
memset(vi,0,sizeof(vi));
top=dfs_time=ans=0;
while(m--){
scanf("%d%d",&u,&v);
Unit(u,v);
};
dfs(1,-1);
dfs1
(1);
memset(vi,0,sizeof(vi));
for(i=1;i<=n;i++)if(in[low[i]]==1&&!
vi[low[i]])
{
vi[low[i]]=1;
ans++;
}
//树添加(ye+1)/2就成为bian双联通
cout<<(ans+1)/2<}
return0;
}
强联通分量
voiddfs(intu)
{
pre[u]=low[u]=++dfs_time;
inti,v;
s.push(u);
vi[u]=1;
for(i=0;i{
v=qe[u][i];
if(!
pre[v]){
dfs(v);
low[u]=min(low[u],low[v]);
}
if(vi[v]&&pre[v]low[u]=pre[v];
}
if(pre[u]==low[u])
{
cnt++;
while
(1)
{
v=s.top();s.pop();
scc[v]=cnt;
vi[v]=0;
if(v==u)break;
}
}
return;
}
intmain()
{
inti,n,m,k,j;
//freopen("in.txt","r",stdin);
while(scanf("%d",&n)!
=EOF)
{
for(i=1;i<=n;i++)
{
qe[i].clear();
while
(1)
{
scanf("%d",&m);
if(!
m)break;
qe[i].push_back(m);
}
}
cnt=dfs_time=0;
memset(pre,0,sizeof(pre));
memset(vi,0,sizeof(vi));
while(!
s.empty())s.pop();
for(i=1;i<=n;i++)if(!
pre[i])
dfs(i);
if(cnt==1)////注意
{
cout<<"1\n0"<continue;
}
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(i=1;i<=n;i++)
{
for(j=0;j{
m=qe[i][j];
if(scc[m]!
=scc[i])
{
in[scc[m]]++;
out[scc[i]]++;
}
}
}
intsum1=0,sum2=0;
for(i=1;i<=cnt;i++)
{
if(out[i]==0)sum2++;
if(in[i]==0)sum1++;
}
cout<}
return0;
}
求割点
voiddfs(intu)
{
pre[u]=low[u]=++dfs_time;
inti,v;
vi[u]=true;
for(i=0;i{
v=qe[u][i];
if(!
vi[v]){
dfs(v);
low[u]=min(low[u],low[v]);
if(low[v]>=pre[u]&&u!
=1)
so[u]++;
elseif(u==1)cnt++;
}
elselow[u]=min(low[u],pre[v]);
}
}
intmain()
{
inti,n,m,k,j;
intu,v;
chara;
freopen("in.txt","r",stdin);
while(scanf("%d",&n)&&n)
{
for(i=1;i<=n;i++)
qe[i].clear();
while(scanf("%d",&u)&&u)
{
while(getchar()!
='\n'){
scanf("%d",&v);
qe[u].push_back(v);
qe[v].push_back(u);
}
}
cnt=dfs_time=0;
memset(pre,0,sizeof(pre));
memset(vi,0,sizeof(vi));
memset(so,0,sizeof(so));
dfs
(1);
intsum1=0;
for(i=1;i<=n;i++)
if(so[i])sum1++;
if(cnt>1)sum1++;
cout<}
return0;
}
割边+最长路
#pragmacomment(linker,"/STACK:
1024000000,1024000000")
usingnamespacestd;
voidUnit(intu,intv)
{
next1[top]=head[u];to[top]=v;
head[u]=top++;
next1[top]=head[v];to[top]=u;
head[v]=top++;
}
voiddfs(intu,intfa)
{
intv,i,cnt1=0;
intx=u;
dp[u][0]=dp[u][1]=0;
pre[u]=low[u]=++dfs_time;
for(i=head[u];i!
=-1;i=next1[i])
{
v=to[i];
if(!
pre[v])
{
dfs(v,u);
low[u]=min(low[u],low[v]);
if(pre[u]cnt++;
inttt=dp[v][0]+(pre[x]if(tt>dp[x][0])
{
dp[x][1]=dp[x][0];dp[x][0]=tt;
}
elseif(tt>dp[x][1])
dp[x][1]=tt;
}
elseif(v==fa)
{
if(cnt1)low[u]=min(low[u],pre[v]);
cnt1++;
}
elselow[u]=min(low[u],pre[v]);
}
}
intmain()
{
intn,m,i,j;
intu,v;
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&m)!
=EOF)
{
if(n+m==0)break;
mem