[POI2012]Festival

题目大意:
  有$n$个正整数$x_1,x_2,\ldots,x_n$,再给出一些限制条件,限制条件分为两类:
    1.给出$A,B$,要求满足$X_A+1=X_B$;
    2.给出$C,D$,要求满足$X_C\leq X_D$。
  其中第1类限制条件有$m_1$个,第2类限制条件有$m_2$个。
  问这些限制条件是否能都被满足,如果能,求集合$\{x_i\}$大小的最大值。

思路:
  不难想到这是一个差分约束模型。
  对于第1类限制,连一条权值为$1$的边$A\to B$,和一条权值为$-1$的边$B\to A$。
  对于第2类限制,连一条权值为$0$的边$C\to D$。
  这种连边方法很经典,难点在于连边以后如何求出集合大小的最大值。
  对于同一个SCC,我们只要跑一下最长路就可以唯一确定当前SCC的权值集合大小,因此我们可以先跑一遍Tarjan,然后Floyd求最长路。
  考虑不同SCC的关系。
  Tarjan缩完点以后就变成了一个DAG,且DAG上的边一定对应第2类限制(不然一定对称,就变成SCC了)。
  我们不妨假设不同SCC中的权值互不重叠,那么我们只需要将所有SCC的答案加起来即可。

  1 #include<stack>
  2 #include<cstdio>
  3 #include<cctype>
  4 #include<vector>
  5 #include<algorithm>
  6 inline int getint() {
  7     register char ch;
  8     while(!isdigit(ch=getchar()));
  9     register int x=ch^'0';
 10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 11     return x; 
 12 }
 13 const int inf=0x7fffffff;
 14 const int N=601;
 15 struct Edge {
 16     int to,w;
 17 };
 18 bool ins[N];
 19 std::stack<int> s;
 20 std::vector<Edge> e[N];
 21 int dis[N][N],low[N],dfn[N],scc[N];
 22 inline void add_edge(const int &u,const int &v,const int &w) {
 23     e[u].push_back((Edge){v,w});
 24 }
 25 void tarjan(const int &x) {
 26     low[x]=dfn[x]=++dfn[0];
 27     s.push(x);
 28     ins[x]=true;
 29     for(unsigned i=0;i<e[x].size();i++) {
 30         const int &y=e[x][i].to;
 31         if(!dfn[y]) {
 32             tarjan(y);
 33             low[x]=std::min(low[x],low[y]);
 34         } else if(ins[y]) {
 35             low[x]=std::min(low[x],dfn[y]);
 36         }
 37     }
 38     if(low[x]==dfn[x]) {
 39         scc[0]++;
 40         int y=0;
 41         while(y!=x) {
 42             ins[y=s.top()]=false;
 43             s.pop();
 44             scc[y]=scc[0];
 45         }
 46     }
 47 }
 48 int main() {
 49     const int n=getint(),m1=getint(),m2=getint();
 50     for(register int i=1;i<=n;i++) {
 51         for(register int j=1;j<=n;j++) {
 52             if(i!=j) {
 53                 dis[i][j]=-inf;
 54             }
 55         }
 56     }
 57     for(register int i=0;i<m1;i++) {
 58         const int u=getint(),v=getint();
 59         add_edge(u,v,1);
 60         add_edge(v,u,-1);
 61         dis[u][v]=std::max(dis[u][v],1);
 62         dis[v][u]=std::max(dis[v][u],-1);
 63     }
 64     for(register int i=0;i<m2;i++) {
 65         const int u=getint(),v=getint();
 66         add_edge(u,v,0);
 67         dis[u][v]=std::max(dis[u][v],0);
 68     }
 69     for(register int i=1;i<=n;i++) {
 70         if(!dfn[i]) {
 71             tarjan(i);
 72         }
 73     }
 74     int ans=0;
 75     for(register int c=1;c<=scc[0];c++) {
 76         for(register int k=1;k<=n;k++) {
 77             if(scc[k]!=c) continue;
 78             for(register int i=1;i<=n;i++) {
 79                 if(scc[i]!=c||dis[i][k]==-inf) continue;
 80                 for(register int j=1;j<=n;j++) {
 81                     if(scc[j]!=c||dis[k][j]==-inf) continue;
 82                     dis[i][j]=std::max(dis[i][j],dis[i][k]+dis[k][j]);
 83                 }
 84             }
 85         }
 86         int tmp=0;
 87         for(register int i=1;i<=n;i++) {
 88             if(scc[i]!=c) continue;
 89             for(register int j=1;j<=n;j++) {
 90                 if(scc[j]!=c) continue;
 91                 tmp=std::max(tmp,std::abs(dis[i][j]));
 92             }
 93         }
 94         ans+=tmp+1;
 95     }
 96     for(register int i=1;i<=n;i++) {
 97         if(dis[i][i]) {
 98             puts("NIE");
 99             return 0;
100         }
101     }
102     printf("%d\n",ans);
103     return 0;
104 }

 

posted @ 2018-01-07 20:03  skylee03  阅读(155)  评论(0编辑  收藏  举报