[BZOJ2788][Poi2012]Festival(差分约束+floyed+tarjan)

来源:互联网 发布:计算机网络就业 知乎 编辑:程序博客网 时间:2024/05/19 12:23

题目描述

传送门

题目大意:有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}大小的最大值。

题解

首先差分约束建图+深搜spfa判断负环->无解
tarjan缩点,不同强连通分量里的点不影响(取值可以没有交集),相同强连通分量里的点的最大取值数为任意两点的最短路的最大值+1
最短路是满足差分约束的条件,可以发现最长的最短路上的点的点权可以按照边权递增,不在这条路上的点的取值一定是它的子集
更科学一点的证明参考popoqqq大爷的题解orz:http://blog.csdn.net/popoqqq/article/details/48249845

代码

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 605#define E 300005int n,m1,m2,dfs_clock,top,scc,ans;int tot,point[N],nxt[E],v[E],c[E];int dis[N],d[N][N],dfn[N],low[N],belong[N],stack[N];bool vis[N],flag;void add(int x,int y,int z){    d[x][y]=min(d[x][y],z);    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;}void spfa(int x){    vis[x]=1;    for (int i=point[x];i;i=nxt[i])        if (dis[v[i]]>dis[x]+c[i])        {            dis[v[i]]=dis[x]+c[i];            if (vis[v[i]])            {                flag=1;                return;            }            spfa(v[i]);            if (flag) return;        }    vis[x]=0;}void floyed(){    for (int k=1;k<=n;++k)        for (int i=1;i<=n;++i)            if (k!=i)                for (int j=1;j<=n;++j)                    if (k!=j)                        d[i][j]=min(d[i][j],d[i][k]+d[k][j]);}void tarjan(int x){    dfn[x]=low[x]=++dfs_clock;stack[++top]=x;vis[x]=1;    for (int i=point[x];i;i=nxt[i])        if (!dfn[v[i]])        {            tarjan(v[i]);            low[x]=min(low[x],low[v[i]]);        }        else if (vis[v[i]])            low[x]=min(low[x],dfn[v[i]]);    if (low[x]==dfn[x])    {        int now=0;++scc;        while (now!=x)        {            now=stack[top--];            belong[now]=scc;            vis[now]=0;        }    }}int main(){    scanf("%d%d%d",&n,&m1,&m2);    memset(d,127/3,sizeof(d));    for (int i=1;i<=n;++i) d[i][i]=0;    for (int i=1;i<=m1;++i)    {        int x,y;scanf("%d%d",&x,&y);        add(x,y,1);add(y,x,-1);    }    for (int i=1;i<=m2;++i)    {        int x,y;scanf("%d%d",&x,&y);        add(y,x,0);    }    for (int i=1;i<=n;++i) add(0,i,0);    memset(dis,127/3,sizeof(dis));dis[0]=0;    flag=0;spfa(0);    if (flag) {puts("NIE");return 0;}    floyed();    memset(vis,0,sizeof(vis));    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 (belong[j]==i)                for (int k=1;k<=n;++k)                    if (belong[k]==i)                        now=max(now,d[j][k]);        ans+=now+1;    }    printf("%d\n",ans);}
0 0
原创粉丝点击