您的位置:首页 > Web前端

[Poi2012]Festival

2017-08-14 11:30 183 查看
4000

问题 D: [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 21 23 41 43 1

样例输出

3

提示

|X3=1, X1=X4=2, X2=3

这样答案为3。容易发现没有更大的方案。

solution

    首先想到差分约束。对于限制2,Xc<=Xd,我们可以把它导成Xc-Xd<=0,由d向c建一条边权为0的边。对于限制1,我们可以转换成Xa+1<=Xb Xa+1>=Xb,然后再导成Xa-Xb<=-1 Xb-Xa<=1,由b向a建一条边权为-1的边,由a向b建一条边权为1的边。注意如果之前已经在两点之间建过边,边权取最小值。

    然后我们开始在图上跑。由于需要满足条件,我们跑最短路。先用tarjan缩点,在每一个环里跑两点之间距离的最小值。如果跑出来发现dis[i][i]不为0,说明不能满足条件。如果能满足,取每个环里两点之间距离绝对值的最大值,相加即为集合最大的大小。

附上代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct tree{
int u,v,next,d;
}l[301000];
int n,m1,m2,lian[605],e,dis[605][605];
int low[605],dfn[605],num,fa[605],cnt,head,st[605];
bool pd[605];
void bian(int,int,int);
void tarjan(int);
int mmin(int x,int y)
{
if(x>y) return y;
return x;
}
int mmax(int x,int y)
{
if(x>y) return x;
return y;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&m1,&m2);
memset(dis,30,sizeof(dis));
for(int i=1;i<=m1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
bian(y,x,-1);
bian(x,y,1);
dis[y][x]=mmin(dis[y][x],-1);
dis[x][y]=mmin(dis[x][y],1);
}
for(int i=1;i<=m2;i++)
{
int x,y;
scanf("%d%d",&x,&y);
bian(y,x,0);
dis[y][x]=mmin(dis[y][x],0);
}
for(int i=1;i<=n;i++)
if(dfn[i]==0)
tarjan(i);
for(int i=1;i<=n;i++)
dis[i][i]=0;
for(int i=1;i<=cnt;i++)
for(int j=1;j<=n;j++)
{
if(fa[j]!=i) continue;
for(int k=1;k<=n;k++)
{
if(fa[k]!=i) continue;
for(int l=1;l<=n;l++)
{
if(fa[l]!=i) continue;
dis[k][l]=mmin(dis[k][l],dis[k][j]+dis[j][l]);
}
}
}
bool cun=0;
for(int i=1;i<=n;i++)
if(dis[i][i]!=0)
{
cun=1;break;
}
if(cun==1)
{
printf("NIE");
return 0;
}
else
{
int zui=0;
for(int i=1;i<=cnt;i++)
{
int mx=0;
for(int j=1;j<=n;j++)
{
if(fa[j]!=i) continue;
for(int k=1;k<=n;k++)
{
if(fa[k]!=i) continue;
mx=mmax(abs(dis[j][k]),mx);
}
}
zui+=mx;
++zui;
}
printf("%d",zui);
}
return 0;
}
void bian(int x,int y,int z)
{
e++;
l[e].u=x;
l[e].v=y;
l[e].d=z;
l[e].next=lian[x];
lian[x]=e;
}
void tarjan(int x)
{
++num;
dfn[x]=num;
low[x]=num;
pd[x]=1;
st[++head]=x;
for(int i=lian[x];i;i=l[i].next)
{
int v=l[i].v;
if(dfn[v]==0)
{
tarjan(v);
low[x]=mmin(low[x],low[v]);
}
else
if(pd[v]==1)
low[x]=mmin(dfn[v],low[x]);
}
if(dfn[x]==low[x])
{
cnt++;
while(1)
{
int tmp=st[head];head--;
fa[tmp]=cnt;
pd[tmp]=0;
if(tmp==x) break;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: