先把这个东西建成差分约束。
跑一遍floyd,如果有负环一定无解。
用tarjan缩点,由于缩完点是一个拓扑图,所以每个强连通分量中的取值是互不影响的(因为可以把拓扑序大的强连通分量中的值无限减少)。所以可以将每个强连通分量的答案相加。
然后对于一个强连通分量的答案是这个强连通分量中的点两两之间最长路的最大值+1。
因为所有权值都是0,1,-1,因此从最小值到最大值的所有值都会取到。由于从最小值到最大值一定存在一条路径,因此答案最大为这个。
又由于差分约束如果有解那么一个环中的一段路径(不为整个环)一定可以满载,因此这是可以取到的。
#include <bits/stdc++.h>
using namespace std;
#define N 810
#define M 210000
int n,m1,m2,tot,cnt,top,scc,ans;
int mp[N][N],head[N],nex[M],to[M];
int deep[N],low[N],st[N],ins[N],bel[N];
void add(int x,int y)
{
nex[++tot]=head[x];head[x]=tot;
to[tot]=y;
}
void tarjan(int x)
{
deep[x]=low[x]=++cnt;
st[++top]=x;ins[x]=1;
for(int i=head[x];i;i=nex[i])
{
if(!deep[to[i]])
tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
else if(ins[to[i]])
low[x]=min(low[x],deep[to[i]]);
}
if(deep[x]==low[x])
{
int tmp=st[top--];
bel[tmp]=++scc;ins[tmp]=0;
while(tmp!=x)
{
bel[tmp=st[top--]]=scc;
ins[tmp]=0;
}
}
}
int main()
{
//freopen("tt.in","r",stdin);
memset(mp,0x3f,sizeof(mp));
scanf("%d%d%d",&n,&m1,&m2);
for(int i=1;i<=n;i++)mp[i][i]=0;
for(int i=1,x,y;i<=m1;i++)
{
scanf("%d%d",&x,&y);
mp[x][y]=min(mp[x][y],1);
mp[y][x]=min(mp[y][x],-1);
add(x,y);add(y,x);
}
for(int i=1,x,y;i<=m2;i++)
{
scanf("%d%d",&x,&y);
mp[y][x]=min(mp[y][x],0);
add(y,x);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
mp[j][k]=min(mp[j][k],mp[j][i]+mp[i][k]);
for(int i=1;i<=n;i++)
if(mp[i][i]<0)return puts("NIE"),0;
for(int i=1;i<=n;i++)
if(!deep[i])tarjan(i);
for(int i=1;i<=scc;i++)
{
int mn=0;
for(int j=1;j<=n;j++)
if(bel[j]==i)
for(int k=1;k<=n;k++)
if(bel[k]==i)
mn=max(mn,mp[j][k]);
ans+=mn+1;
}
printf("%d\n",ans);
return 0;
}