少有的差分约束。
按照差分约束的规则建边。
然后就可以搞事情了。
n辣么小,是不是可以floyd warshall算法就可以了?
而且floyd可以干很多事。
比如判负环。。。
对于本题不用floyd(FIFO队列(SPFA)和双端队列(麻辣烫优化)优化的贝尔曼福特算法对于这么大的边我认为还不如简单易懂的floyd)判断不了负环(tarjan的本质是判断强连通,环套环也是负环啊,对于差分约束有负环就是有问题)
然后tarjan缩点。
接着利用floyd求最长链。枚举一个环的两个端点取MAX+1
然后利用贪心的思想便利每一个scc
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
using namespace std;
const int N=1200;
struct Front_star{
int u,v,w,nxt;
}e[400500];
int cnt=0;
int first[N]={0};
void add(int u,int v,int w){
cnt++;
e[cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].nxt=first[u];
first[u]=cnt;
}
int n,m1,m2;
int g[701][701]={0};
//
int vis[N]={0};
int dfn[N]={0};
int low[N]={0};
int color[N]={0};
int scc=0;
int tot=0;
stack<int> S;
void tarjan(int u){
tot++;
dfn[u]=tot;
low[u]=tot;
vis[u]=1;
S.push(u);
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}
else{
if(vis[v]){
low[u]=min(low[u],dfn[v]);
}
}
}
if(low[u]==dfn[u]){
int x;
scc++;
do{
x=S.top();
S.pop();
vis[x]=0;
color[x]=scc;
}while(x!=u);
}
}
int main(){
scanf("%d%d%d",&n,&m1,&m2);
memset(g,0x3f,sizeof(g));
for(int i=1;i<=m1;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v,1);
g[u][v]=min(g[u][v],1);
add(v,u,-1);
g[v][u]=min(g[v][u],-1);
}
for(int i=1;i<=m2;i++){
int u,v;
scanf("%d%d",&u,&v);
add(v,u,0);
g[v][u]=min(g[v][u],0);
}
for(int i=1;i<=n;i++){
g[i][i]=0;
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
g[i][j]=min(g[i][k]+g[k][j],g[i][j]);
}
}
}
for(int i=1;i<=n;i++){
if(g[i][i]<0){
printf("NIE\n");
return 0;
}
}
for(int i=1;i<=n;i++){
if(!dfn[i])
tarjan(i);
}
int ans=0;
// cout<<scc<<'\n';
for(int i=1;i<=scc;i++){
int now=0;
for(int j=1;j<=n;j++){
if(color[j]==i){
for(int k=1;k<=n;k++){
if(j==k)
continue;
if(color[k]==i){
now=max(now,g[j][k]);
}
}
}
}
ans+=now+1;
}
cout<<ans;
}