题意:链接
方法:差分约束+tarjan+floyd
解析:
说实话蛮简单的题。
不过考试的时候差分约束都忘光了,连完边就不到咋搞了=-=,于是强行spfa求奇怪的东西骗分来着。
然并卵
首先我们能建出差分约束系统。
然后我们考虑对于每个强连通分量。
内部的答案依据差分约束显然是最长路+1.
但是如果两个相连接的强连通分量怎么办呢。
依据题中的要求,xc<=xd,所以我们可以想像,相连接的强连通分量一定是由0边连接的。所以我们可以极限考虑一下,即一个强连通分量里的值无限小,另一个无限大(无限大な梦のあとの 何もない世の中じゃ),也就是说,二者的取值是不影响的。
所以我们只需要求出每个强连通分量内的答案,最后求和即可。
任意两点最长路对于n<=600肯定会考虑floyd,不要问我为什么复杂度允许,剪枝很多的话复杂度是玄学。
另外,如果出现正权环的话就是NIE。
如何判断正权环呢?
初始化map[i][i]=0,跑完floyd后看是否还是0即可。
复杂度 O(玄学),最坏O(n^3)不虚。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 610
#define M 200010
#define INF 0x3f3f3f3f
using namespace std;
int n,m1,m2,cnt,tot,top,num;
int head[N];
int deep[N],low[N],sta[N],ins[N],v[N],belong[N];
int map[N][N],vw[N][N];
struct node
{
int from,to,val,next;
}edge[M];
void init()
{
memset(head,-1,sizeof(head));
cnt=1;
}
void edgeadd(int from,int to,int val)
{
edge[cnt].from=from,edge[cnt].to=to,edge[cnt].val=val;
edge[cnt].next=head[from],head[from]=cnt++;
}
void tarjan(int now)
{
deep[now]=low[now]=++tot;
ins[now]=1,sta[++top]=now;
for(int i=head[now];i!=-1;i=edge[i].next)
{
int to=edge[i].to;
if(!deep[to])
{
tarjan(to);
low[now]=min(low[now],low[to]);
}else if(ins[to])low[now]=min(low[now],deep[to]);
}
if(deep[now]==low[now])
{
int t;
num++;
do
{
t=sta[top--];
belong[t]=num;
ins[t]=0;
}while(t!=now);
}
}
int main()
{
init();
scanf("%d%d%d",&n,&m1,&m2);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
map[i][j]=-INF;
for(int i=1;i<=n;i++)map[i][i]=0;
for(int i=1;i<=m1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
edgeadd(x,y,1);
edgeadd(y,x,-1);
map[x][y]=max(map[x][y],1),map[y][x]=max(map[y][x],-1);
}
for(int i=1;i<=m2;i++)
{
int x,y;
scanf("%d%d",&x,&y);
edgeadd(x,y,0);
map[x][y]=max(map[x][y],0);
}
for(int i=1;i<=n;i++)
{
if(!deep[i])tarjan(i);
}
int ans=0;
for(int b=1;b<=num;b++)
{
int ret=0;
for(int k=1;k<=n;k++)
{
if(belong[k]!=b)continue;
for(int i=1;i<=n;i++)
{
if(belong[i]!=b)continue;
if(map[i][k]==-INF)continue;
for(int j=1;j<=n;j++)
{
if(belong[j]!=b)continue;
if(map[k][j]==-INF)continue;
map[i][j]=max(map[i][j],map[i][k]+map[k][j]);
}
}
}
for(int i=1;i<=n;i++)
{
if(belong[i]!=b)continue;
for(int j=1;j<=n;j++)
{
if(belong[j]!=b)continue;
ret=max(ret,abs(map[i][j]));
}
}
ans+=ret+1;
}
for(int i=1;i<=n;i++)if(map[i][i]!=0){puts("NIE");return 0;}
printf("%d\n",ans);
}