1. 程式人生 > >BZOJ 2788 [Poi2012]Festival 差分約束+tarjan+floyd

BZOJ 2788 [Poi2012]Festival 差分約束+tarjan+floyd

題意:連結

方法:差分約束+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); }