[Poi2012]Festival
时间限制: 1 Sec 内存限制: 64 MB
题目描述
有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}大小的最大值。
输入
第一行三个正整数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),表示第二类限制。
输出
一个正整数,表示集合{Xi}大小的最大值。
如果无解输出NIE。
样例输入
4 2 2 1 2 3 4 1 4 3 1
样例输出
3
提示
|X3=1, X1=X4=2, X2=3
这样答案为3。容易发现没有更大的方案。
先膜拜一下Q某犇,他给我讲的这道题。
这道题基本一看就是差分约束,建边已经是套路了,问题在于如何乱搞找出正解。首先,我们可以看出每一个强联通分量对答案的贡献与其他强联通分量无关,因为他们之间建边的话只能是某几个单向的0边,又因为Xi无限制,所以完全是可以对每个强联通分量单独结算在合并的。
那么我们怎么求在单个强联通分量的最大大小呢?floyd最长路就好了。反正n<=600这道题想卡你的话貌似也不太容易,因此我们大可将每个强联通分量中的点建一个链表,复杂度就大大降低了。
而有没有接嘛,只要看跑完floyd之后dis[i][i]是否为0就好了。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<string>
#include<cmath>
#define N 750
using namespace std;
int n,m1,m2;
int zz,dis[N][N];
bool rz[N],rz2[N];
int dfn[N],low[N],st[N],zz2,top;
int be[N],zz3,pre[N];
int mx[N];
void tar(int x){
zz2++;
dfn[x]=low[x]=zz2;
rz[x]=rz2[x]=;
top++;
st[top]=x;
for(int i=;i<=n;i++)
{
if(dis[x][i]!=dis[][]&&i!=x)
{
if(!rz2[i])
{
tar(i);
low[x]=min(low[x],low[i]);
}
else if(rz[i])
{
low[x]=min(low[x],dfn[i]);
}
}
}
if(low[x]==dfn[x])
{
zz3++;
int v,la=;
do{
v=st[top];
top--;
rz[v]=;
if(!be[zz3])
be[zz3]=v;
pre[la]=v;
la=v;
}while(dfn[v]!=low[v]);
}
}
int main(){
memset(pre,-,sizeof(pre));
scanf("%d%d%d",&n,&m1,&m2);
memset(dis,-0xf,sizeof(dis));
for(int i=;i<=m1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
dis[x][y]=max(dis[x][y],);
dis[y][x]=max(-,dis[y][x]);
}
for(int i=;i<=m2;i++)
{
int x,y;
scanf("%d%d",&x,&y);
dis[x][y]=max(dis[x][y],);
}
for(int i=;i<=n;i++)
{
if(!rz2[i])
{
tar(i);
}
} for(int i=;i<=n;i++)
{
dis[i][i]=;
}
for(int o=;o<=zz3;o++)
{
for(int k=be[o];k!=-;k=pre[k])
{
for(int i=be[o];i!=-;i=pre[i])
{
for(int j=be[o];j!=-;j=pre[j])
{
if(abs(dis[i][k])<=n&&abs(dis[k][j])<=n)
dis[i][j]=max(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
for(int i=be[o];i!=-;i=pre[i])
{
for(int j=be[o];j!=-;j=pre[j])
mx[o]=max(mx[o],abs(dis[i][j]));
}
}
for(int i=;i<=n;i++)
{
if(dis[i][i]!=)
{
printf("NIE\n");
exit();
}
} int ans=;
for(int i=;i<=zz3;i++)
ans+=mx[i]+;
printf("%d\n",ans);
// while(1);
return ;
}