BZOJ 2788 [Poi2012]Festival 差分約束+tarjan+floyd
阿新 • • 發佈:2018-12-24
題意:連結
方法:差分約束+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);
}