2788: [Poi2012]Festival
Time Limit: 30 Sec Memory Limit: 64 MB[ Submit][ Status][ Discuss]
Description
有n个正整数X1,X2,...,Xn,再给出m1+m2个限制条件,限制分为两类:
1. 给出a,b (1<=a,b<=n),要求满足Xa + 1 = Xb
2. 给出c,d (1<=c,d<=n),要求满足Xc <= Xd
在满足所有限制的条件下,求集合{Xi}大小的最大值。
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 1
1 2
3 4
1 4
3 1
Sample Output
3
HINT
|X3=1, X1=X4=2, X2=3
这样答案为3。容易发现没有更大的方案。
Source
差分约束建图先
首先跑一遍Floyd,如果一个点到自己的距离都小于0了,NIE!
然后tarjan缩点,可以想到各个环中各不影响(其实是贪到)
在一个环中如何统计最大点数?
我们可以知道,由于距离绝对值不大于1,假设在数轴上,一个环内所有点紧靠,那么可以取的个数就是
环内最大距离+1
这道题我跑了16000+,有人跑了400+,都怪floyd太暴力了,由于我是懒癌所以。。就floyd吧
非常暴力的代码,邻接表还有个没用的v,懒得去了
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 600 + 5;
const int M = 2000000 + 5;
struct Edge{
int to,next;
}e[M];
int last[N*2],cnt;
void insert( int u, int v, int w ){ e[++cnt].to = v; e[cnt].next = last[u]; last[u] = cnt; }
int mp[N][N],dfn[N],low[N],scc,sta[N],cot,n,m1,m2,top,bel[N],ans; bool inq[N];
void tarjan( int x ){
low[x] = dfn[x] = ++cot;
sta[++top] = x; inq[x] = 1;
for( int i = last[x]; i; i = e[i].next )
if( !dfn[e[i].to] ) tarjan(e[i].to),low[x]=min(low[x],low[e[i].to]);
else if( inq[e[i].to] ) low[x] = min(low[x],dfn[e[i].to]);
if( dfn[x] == low[x] ){
int now = 0; scc++;
while( now != x ){
now = sta[top--];
bel[now] = scc;
inq[now] = 0;
}
}
}
int main(){
scanf("%d%d%d", &n, &m1, &m2);
memset(mp,0x3f,sizeof(mp));
for( int i = 1,u,v; i <= m1; i++ ){
scanf("%d%d", &u, &v);
mp[u][v] = min(mp[u][v],1); mp[v][u] = min(mp[v][u],-1);
insert( u, v, 1 ); insert( v, u, -1 );
}
for( int i = 1,u,v; i <= m2; i++ ){
scanf("%d%d", &u, &v);
mp[v][u] = min(mp[v][u],0);
insert( v, u, 0 );
}
for( int i = 1; i <= n; i++ ) mp[i][i] = 0;
for( int k = 1; k <= n; k++ )
for( int i = 1; i <= n; i++ )
for( int j = 1; j <= n; j++ )
mp[i][j] = min( mp[i][j], mp[i][k]+mp[k][j] );
for( int i = 1; i <= n; i++ ) if( mp[i][i] < 0 ){ puts("NIE"); return 0; }
for( int i = 1; i <= n; i++ ) if( !dfn[i] ) tarjan(i);
for( int i = 1; i <= scc; i++ ){
int now = 0;
for( int j = 1; j <= n; j++ )
if( bel[j] == i )
for( int k = 1; k <= n; k++ )
if( bel[k] == i )
now = max(now,mp[j][k]);
ans += now+1;
}
printf("%d\n", ans);
return 0;
}