【 [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);
}

浙公网安备 33010602011771号