[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 }