最近在刷图论专题,这道题难度还算可以,顺便复习了一下差分约束。
1、建边
第一种可变形为 -1<=Xa-Xb<=-1 第二种变形为Xc-Xd<=0,根据差分约束,对于第一种,由Xa向Xb建权值为1的边,由Xb向Xa建权值为-1的边。
对于第二种,由Xc向Xd建权值为0的边。
2、tarjan缩点
由第一种构建出来的会出现环,依据差分约束系统,这些强连通分量内部的答案显然是最长路+1,所以tarjan统计出每个强连通分量
3、floyd求最长路
第二种会把这些强连通分量连接起来,所以只需分别求出每个强连通分量的最长路+1,再求sigma。
4、floyd判正环
只需初始化w[i][i]=0,跑完最长路之后看w[i][i]是否仍为0即可。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#define inf -10000000
using namespace std;
struct bian
{
int qi,zhong,w,next;
};
bian c[400010];
int n,m1,m2,jishu=0,jishu1=0,ans=0,jishu2=0,jishu3=0,w[610][610];
int dfn[610],low[610],belong[610],head[610],zhan[610];
bool in[610];
int x,y;
void add(int x,int y,int z)
{
c[++jishu].qi=x;
c[jishu].zhong=y;
c[jishu].w=z;
c[jishu].next=head[x];
head[x]=jishu;
}
void tarjan(int x)
{
dfn[x]=++jishu2;
low[x]=jishu2;
zhan[++jishu3]=x;
in[x]=1;
for(int i=head[x];i;i=c[i].next)
{
if(dfn[c[i].zhong]==-1)
{
tarjan(c[i].zhong);
low[x]=min(low[x],low[c[i].zhong]);
}
else if(in[c[i].zhong])
low[x]=min(low[x],dfn[c[i].zhong]);
}
if(low[x]==dfn[x])
{
int y;
jishu1++;
while(1)
{
y=zhan[jishu3--];
in[y]=0;
belong[y]=jishu1;
if(x==y)
break;
}
}
}
int main()
{
cin>>n>>m1>>m2;
memset(dfn,-1,sizeof(dfn));
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
w[i][j]=inf;
for(int i=1;i<=n;++i)
w[i][i]=0;
for(int i=1;i<=m1;++i)
{
cin>>x>>y;
add(x,y,1);
add(y,x,-1);
w[x][y]=max(w[x][y],1);
w[y][x]=max(w[y][x],-1);
}
for(int i=1;i<=m2;++i)
{
cin>>x>>y;
add(x,y,0);
w[x][y]=max(w[x][y],0);
}
for(int i=1;i<=n;++i)
if(dfn[i]==-1)
tarjan(i);
for(int i=1;i<=jishu1;++i)
{
int da=inf;
for(int k=1;k<=n;++k)
{
if(belong[k]!=i) continue;
for(int j=1;j<=n;++j)
{
if(belong[j]!=i||w[j][k]==inf) continue;
for(int l=1;l<=n;++l)
{
if(belong[l]!=i||w[k][l]==inf) continue;
if(w[j][l]<w[j][k]+w[k][l])
w[j][l]=w[j][k]+w[k][l];
}
}
}
for(int j=1;j<=n;++j)
{
if(belong[j]!=i) continue;
for(int k=1;k<=n;++k)
{
if(belong[k]!=i||w[j][k]==inf) continue;
da=max(da,abs(w[j][k]));
}
}
ans+=da+1;
}
for(int i=1;i<=n;++i)
if(w[i][i])
{
cout<<"NIE";
return 0;
}
cout<<ans;
return 0;
}