首页 > 代码库 > 共荣圈

共荣圈

P2419 - 共荣圈

Description

某岛国地形狭长,中部多山,东西海岸线上各有N/2个 城市,有M条高速公路连接东西部的城市。为促进经济共同繁荣,该国政府决定建立一些“经济共荣 圈”。已知一个“共荣圈”由东西部各一个城市组成。每个城市要么不属于任何一个“共荣圈”,要么只属于一个“共荣圈”。“共荣圈”中的两个城市之间必须有 高速公路直接相连。该岛国政府经过分析,发现最多能够建立W个“共荣圈”。
A国认为“共荣圈”的建立不利于世界和平,决定出面干涉该岛国“共荣圈”的建立。通过各种手段,A国购买了一条高速公路,并禁止这条高速 公路的通行。被禁止通行这条高速公路的两端的两个城市之间如果没有其他道路相连接,将不能建立“共荣圈”。为尽可能得阻止“共荣圈”的建立,A国购买的这 条道路的选择很重要。A国想知道它有多少种购买选择,可以使该岛国无法建成W个“共荣圈”。

Input

第一行,两个整数N,M,表示一共的城市个数和道路数。
接下来M行,每行两个整数A,B,表示西部城市A与东部城市B之间有一条高速公路直接连接,其中1<=A<=N/2,N/2+1<=B<=N。

Output

一个整数,表示A国购买的这一条道路的可行选择数目。

Sample Input

8 5
1 5
1 6
2 7
3 7
4 8

Sample Output

1

Hint

样例说明

该国最多能建立的“共荣圈”数量为3,购买并封锁(4,8)这条道路后,最多能建立的“共荣圈”数量减少为2。

数据规模

对于40%的数据
2<=N<=200
1<=M<=1000
对于100%的数据
2<=N<=100000
1<=M<=100000
保证N为偶数 ,数据可能会有重边

 

 

<style>pre.cjk { font-family: "Droid Sans Fallback", monospace } p { margin-bottom: 0.25cm; line-height: 120% } a:link { }</style>
暴力50分,枚举每一条边,删掉,跑m遍最大流。
先跑一遍最大流,然后在残余网络上跑Tarjan求强连通分量。
枚举每一条边,若这条边是有流量的边,且这条边连接的两个点在不同的SCC里面,
则答案+1。因为若这两个点在同一个SCC里,就有另外一条路径从起点流向终点,则这条边删除之后对答案没有影响。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 100010
#define inf 1999999999
#define RG register
using namespace std;
struct data{
  int nex,to,w,from;
}e[maxn*6];
int head[maxn],edge=-1,lev[maxn];
int scc[maxn],dfn[maxn],low[maxn];
inline int Read(){
  int x=0;char ch=getchar();
  while(ch<0 || ch>9) ch=getchar();
  while(ch>=0 && ch<=9){x=x*10+ch-0;ch=getchar();}
  return x;
}
inline void add(int from,int to,int w){
  e[++edge].nex=head[from];
  e[edge].to=to;
  e[edge].w=w;
  e[edge].from=from;
  head[from]=edge;
}
int Min(int a,int b){if(a>b) return b;else return a;}
int q[maxn*10];
inline bool bfs(int s,int t){
  memset(lev,0,sizeof(lev));
  int hed=0,tail=1;
  lev[s]=1;
  q[tail]=s;
  while(hed<tail){
    hed++;
    int u=q[hed];
    for(RG int i=head[u];i!=-1;i=e[i].nex)
      if(!lev[e[i].to] && e[i].w>0){
    lev[e[i].to]=lev[u]+1;
    if(e[i].to==t) return 1;
    else q[++tail]=e[i].to;
      }
  }
  return 0;
}
int dfs(int s,int t,int k){
  if(s==t) return k;
  int rag=0;
  for(RG int i=head[s];i!=-1;i=e[i].nex)
    if(e[i].w>0 && lev[e[i].to]==lev[s]+1){
      int d=dfs(e[i].to,t,Min(k-rag,e[i].w));
      e[i].w-=d;
      e[i^1].w+=d;
      rag+=d;
      if(rag==k) return rag;
    }
  return rag;
}
int de=0,sccno=0;
int S[maxn*10],top=0;
void tarjan(int x){
  ++de;dfn[x]=low[x]=de;
  S[++top]=x;
  for(RG int i=head[x];i!=-1;i=e[i].nex)
    if(e[i].w<=0){
      int u=e[i].to;
      if(!dfn[u]){
    tarjan(u);
    low[x]=Min(low[x],low[u]);
      }
      else if(!scc[u]) low[x]=Min(low[x],dfn[u]);
    }
  if(low[x]==dfn[x]){
    ++sccno;
    while(top!=0){
      int u=S[top];top--;
      scc[u]=sccno;
      if(u==x) break;
    }
  }
}
int main()
{
  freopen("!.in","r",stdin);
  freopen("!.out","w",stdout);
  int n,m,x,y;
  memset(head,-1,sizeof(head));
  scanf("%d%d",&n,&m);
  int s=0,t=n+1;
  for(RG int i=1;i<=m;i++)
    x=Read(),y=Read(),add(x,y,1),add(y,x,0);
  int kt=edge;
  for(RG int i=1;i<=n/2;i++) add(s,i,1),add(i,s,0);
  for(RG int i=n/2+1;i<=n;i++) add(i,t,1),add(t,i,0);
  while(bfs(s,t))dfs(s,t,1999999999);
  for(RG int i=s;i<=t;i++)
    if(!scc[i]) tarjan(i);
  int ans=0;
  for(RG int i=0;i<=kt;i+=2){
    if(e[i].w<=0 && scc[e[i].from]!=scc[e[i].to]) ans++;
  }
  printf("%d",ans);
  return 0;
}

 

共荣圈