您的位置:首页 > Web前端

[POI2012]Festival

2018-01-07 20:03 253 查看

题目大意:
  有$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的答案加起来即可。

#include<stack>
#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int inf=0x7fffffff;
const int N=601;
struct Edge {
int to,w;
};
bool ins
;
std::stack<int> s;
std::vector<Edge> e
;
int dis

,low
,dfn
,scc
;
inline void add_edge(const int &u,const int &v,const int &w) {
e[u].push_back((Edge){v,w});
}
void tarjan(const int &x) {
low[x]=dfn[x]=++dfn[0];
s.push(x);
ins[x]=true;
for(unsigned i=0;i<e[x].size();i++) {
const int &y=e[x][i].to;
if(!dfn[y]) {
tarjan(y);
low[x]=std::min(low[x],low[y]);
} else if(ins[y]) {
low[x]=std::min(low[x],dfn[y]);
}
}
if(low[x]==dfn[x]) {
scc[0]++;
int y=0;
while(y!=x) {
ins[y=s.top()]=false;
s.pop();
scc[y]=scc[0];
}
}
}
int main() {
const int n=getint(),m1=getint(),m2=getint();
for(register int i=1;i<=n;i++) {
for(register int j=1;j<=n;j++) {
if(i!=j) {
dis[i][j]=-inf;
}
}
}
for(register int i=0;i<m1;i++) {
const int u=getint(),v=getint();
add_edge(u,v,1);
add_edge(v,u,-1);
dis[u][v]=std::max(dis[u][v],1);
dis[v][u]=std::max(dis[v][u],-1);
}
for(register int i=0;i<m2;i++) {
const int u=getint(),v=getint();
add_edge(u,v,0);
dis[u][v]=std::max(dis[u][v],0);
}
for(register int i=1;i<=n;i++) {
if(!dfn[i]) {
tarjan(i);
}
}
int ans=0;
for(register int c=1;c<=scc[0];c++) {
for(register int k=1;k<=n;k++) {
if(scc[k]!=c) continue;
for(register int i=1;i<=n;i++) {
if(scc[i]!=c||dis[i][k]==-inf) continue;
for(register int j=1;j<=n;j++) {
if(scc[j]!=c||dis[k][j]==-inf) continue;
dis[i][j]=std::max(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
int tmp=0;
for(register int i=1;i<=n;i++) {
if(scc[i]!=c) continue;
for(register int j=1;j<=n;j++) {
if(scc[j]!=c) continue;
tmp=std::max(tmp,std::abs(dis[i][j]));
}
}
ans+=tmp+1;
}
for(register int i=1;i<=n;i++) {
if(dis[i][i]) {
puts("NIE");
return 0;
}
}
printf("%d\n",ans);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: