【 [POI2012]FES-Festival(NKOJ party)】差分约束+tarjan+floyd
想了几个小时无果,真是太弱了orz orz orz
这道题主要是平时总是差分约束和spfa结合,少有来一道差分约束搭配tarjan强联通分量的题,就跪了,说明差分约束还是没要搞透彻额呃呃。
BZOJ2788(权限) Luo3530
2788: [Poi2012]Festival
Time Limit: 30 Sec Memory Limit: 64 MB Submit: 544 Solved: 261 [Submit][Status][Discuss]Description
有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类:- 给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb
- 给出c,d (1<=c,d<=n),要求满足Xc <= Xd
Input
第一行三个正整数n, m1, m2 (2<=n<=600, 1<=m1+m2<=100,000)。 接下来m1行每行两个正整数a,b (1<=a,b<=n),表示第一类限制。 接下来m2行每行两个正整数c,d (1<=c,d<=n),表示第二类限制。Output
一个正整数,表示集合{Xi}大小的最大值。 如果无解输出NIE。Sample Input
4 2 2 1 2 3 4 1 4 3 1Sample Output
3HINT
|X3=1, X1=X4=2, X2=3 这样答案为3。容易发现没有更大的方案。 我们可以非常显而易见地想到图论算法--差分约束,很快连边就写好了。然后。。。(⊙﹏⊙)不会啊啊啊。 好吧,我们分析一下发现其实本质上来说有一二两种边。第一种边是直接卡死了对于两个X的大小关系。他们之间一定有一个-1关系。而第二种边如果不存在和其他的联通块成环(即被卡死在两个范围之间,而要形成两个范围一定会有第一种边进行的限制。那么也就是说,对于一个联通块,一定有一个范围的限制,但对于一个几个联通块之间的边,他们的大小并不会出现限制。可以发现第一种边是直接将两个点放进了一个强联通分量中,到最后联通块之间的边一定是第二种边,而他们之间的选择不会受到影响,那么答案直接对于所有强联通分量中的答案进行累加就可以了。 差分约束我们设定dis[i][j]表示i最多能比j大多少。我们知道差分约束跑最短路最后是求得最大解。在tarjan求出所有强联通分量之后。由于n很小,直接在各个强联通分量内跑floyd,对于负环直接判断如果dis[i][i]<0就有负环(可以想到对于这样的差分约束不应该有负环)。再在各个强联通分量之间找到最大的dis[i][j]+1就可以了(i大于j,dis[i][j],加上i本身的数字总数),然后全部加起来。 code:#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<vector> using namespace std; int n,m1,m2; const int maxm = 200005; const int maxn = 605; bool inst[maxn]; int top; int sta[maxn]; int dfx,dfn[maxn],low[maxn],blo[maxn],scc; int dis1[maxn][maxn]; int la[maxn],nt[maxm],en[maxm],owo; char buf[1<<20],*p1,*p2; vector<int>ve[maxn]; #define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++) inline int R() { char t=GC; int x=0; while(!isdigit(t)) t=GC; while(isdigit(t)) x=x*10+t-48,t=GC; return x; } inline void addedge(int a,int b,int c) { en[++owo] = b; nt[owo] = la[a]; la[a] = owo; dis1[a][b] = min(dis1[a][b],c); } void tarjan(int x) { dfn[x]=low[x]=++dfx; sta[++top] = x; inst[x]=1; for(int it=la[x];it;it=nt[it]) { if(!dfn[en[it]]) { tarjan(en[it]); low[x] = min(low[x],low[en[it]]); } else if(inst[en[it]]) low[x] = min(low[x],dfn[en[it]]); } if(low[x]==dfn[x]) { ++scc; int y; do { y = sta[top--]; inst[y] = 0; blo[y] = scc; ve[scc].push_back(y); }while(y!=x); } } int main() { n=R(); m1 = R(); m2 = R(); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { dis1[i][j] = 0x3f3f3f3f; } dis1[i][i] = 0; } for(int i=1;i<=m1;i++) { int x,y; x=R(); y = R(); addedge(x,y,1); addedge(y,x,-1); } for(int i=1;i<=m2;i++) { int x,y; x=R(); y=R(); addedge(y,x,0); } for(int i=1;i<=n;i++) dis1[i][i] = 0; for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int k=1;k<=n;k++) { int idk = blo[k]; for(int i=1;i<=n;i++) { int idi = blo[i]; if(idi!=idk) continue; for(int j=1;j<=n;j++) { int idj = blo[j]; if(idi!=idj) continue; dis1[i][j] = min(dis1[i][j],dis1[i][k]+dis1[k][j]); } } } for(int i=1;i<=n;i++) if(dis1[i][i]<0) { puts("NIE"); return 0; } int ans = 0; for(int k=1;k<=scc;k++) { int mama = 0; int s = ve[k].size(); for(int i=0;i<s;i++) { for(int j=0;j<s;j++) { mama = max(dis1[ve[k][i]][ve[k][j]],mama); } } ans+=mama+1; } printf("%d",ans); }