血帆海盗

 
 

426.血帆海盗

★★★   输入文件: bloodsail.in   输出文件: bloodsail.out    简单对比 时间限制:2 s   内存限制:128 MB

问题描述  随着资本的扩大,藏宝海湾贸易亲王在卡利姆多和东部王国大陆各建立了N/2 个港口。大灾变发生以后,这些港口之间失去了联系,相继脱离了藏宝海湾贸易亲王的管辖,各自为政。利益的驱动使得每个港口都想和对岸大陆的另一个港口建立贸易合作关系,由于地理位置因素,只有存在直接到达的航线的两个港口才能建立合作,而且每个港口只与对岸一个港口建立合作,因此并不是所有的港口都能找到合作伙伴。    血帆海盗得知这一消息以后,决定对其中一条航线进行干扰性的掠夺。经过分析,血帆海盗计算出最多能有W 对港口合作。如果两个港口之间只有一条航线,而且这条航线恰好是血帆海盗要掠夺的航线,这两个港口将不能建立合作关系。血帆海盗指挥官菲尔拉伦想知道他们有几种选择,可以让地精们无法建立W 对港口。 

输入格式 第1行,两个整数N,M,表示一共的港口个数和航线条数。  接下来M行,每行两个整数A,B,表示卡利姆多的港口A与东部王国的港口B之间有一条航线直接连接,其中1<=A<=N/2,N/2+1<=B<=N。

输出格式 一个整数,表示血帆海盗可以选择掠夺的航线条数。    解释:如果掠夺一条航线以后,地精依然可以建立起最多的W个合作关系(可以有多种), 那么这条航线是不值得掠夺的,否则就是掠夺方案之一。

样例输入  8 5  1 5  1 6  2 7  3 7  4 8

样例输出  1

样例说明  地精做多能建立起合作关系的数量为3,掠夺(4,8)这条航线后,最多能建立的合作关系的 数量减少为2。

数据规模  40%的数据满足2<=N<=200,1<=M<=1000  100%的数据满足2<=N<=100000,1<=M<=100000,保证N为偶数

Tar缩点
 
 
  • 首先按照题意建所有边容量为1的图,求最大流,即最大二分匹配,这个值为w,然后明确流量为0边拆掉是没有意义的,因为w不会改变
  • 对出整个图的强连通分量,此时的图是求最大流后的剩余图,如果一条边的两点不属于同一个强连通分量(已建反向边),那么拆掉这条边就会使得w减小,如果属于同一个强连通分量(a -> b , 流量为1),那么删掉这条边,回到最开始的图就是拆掉边(b -> a , 流量为0),因为在通一个联通分量中,这条边就会别的边代替(因为在一个联通分量中,a能到达b,b能到达a)
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#include<cstdlib>
#include<algorithm>
#define V 100005
#define mod 1073741823
#define LL long long
using namespace std;
int n,m,sd,T,S;//a[V][V],s[V][V],g[V][V],
int pre[V],dep[V],q[V*2];
int top,scc,cnt,G[V*2],dfn[V],low[V],vis[V],bl[V];
struct da
{
 int to,next,dis;       
}Edge[V*5];
int head[V],tot;
inline void add(int x,int y,int zz)
{
  Edge[tot].to=y;
  Edge[tot].dis=zz;
  Edge[tot].next=head[x];
  head[x]=tot++;  
  Edge[tot].to=x;
  Edge[tot].dis=0;
  Edge[tot].next=head[y];
  head[y]=tot++;     
}
bool Bfs() {
    memset(dep, 0, sizeof(dep));
    int hd,tl;
    hd = tl = 0;
    q[++ tl] = S, dep[S] = 1;
    while(hd<tl) {
        int op = q[++hd];
        for(int i = head[op] ; i != -1 ; i = Edge[i].next) {
            if(Edge[i].dis&&(!dep[Edge[i].to])) {
                dep[Edge[i].to] = dep[op]+1;
                q[++ tl] = Edge[i].to;
                if(Edge[i].to==T) return true;
            } 
        }
    }
    return false;
}
int Dfs(int op, int fw) {
    if(op==T) return fw;           
    int tmp =fw,k;
    for(int i = head[op] ; i != -1 ; i = Edge[i].next) {
        if(Edge[i].dis&&tmp&&dep[Edge[i].to]==dep[op]+1) {
            k = Dfs(Edge[i].to, min(Edge[i].dis, tmp));
            if(!k) { 
                dep[Edge[i].to] = 0; 
                continue; 
            }
            Edge[i].dis-= k, Edge[i^1].dis+= k,tmp-= k;
        }
    }
    return fw-tmp;
}
int solve()
{
   int i,flow=0;
   int z;
   while(Bfs())
   {
  // z=Dfs(S,mod);
    //while(z)
    //{
    flow+=Dfs(S,mod); //z;//add();///           
    //z=Dfs(S,mod);
    //}
   }
   return flow;
}
void tar(int x)
{
  int v;
  dfn[x]=low[x]=++cnt;
  G[top++]=x;
  vis[x]=1;
  for(int i=head[x];i!=-1;i=Edge[i].next)
  {
      v=Edge[i].to;
      if(!Edge[i].dis)continue;
      if(!dfn[v])
      {
        tar(v);
        low[x]=min(low[v],low[x]);          
      }
      else if(vis[v])
      {
        low[x]=min(low[x],dfn[v]);     
      }
  }
  if(low[x]==dfn[x])
  {
    scc++;
    while(1)
    {
      v=G[--top];
      bl[v]=scc;
      vis[v]=0;
      if(v==x)break;        
            
    }                  
  }

}
inline int haha()
{
   // freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
     freopen("bloodsail.in","r",stdin); freopen("bloodsail.out","w",stdout);
    memset(head,-1,sizeof(head));
    //cout<<" !! "<<endl;
    cin>>n>>m;
    T=n+1;
    //cout<<S<<" ## "<<T<<endl;
    int x,y,z;
   
    for(int i=1;i<=m;i++)
    {
      //cin>>x>>y>>z;
      scanf("%d%d",&x,&y); 
      //cout<<x<<" "<<y<<endl;
      add(x,y,1);        
    }
    for(int i=1;i<=n/2;i++)
    add(0,i,1);
    for(int i=n/2+1;i<=n;i++)
    add(i,T,1);
    int sb=solve();
    for(int i=1;i<=n;i++)
     if(!dfn[i])tar(i);
     int ans=0;
    for(int i=0;i<=2*m-1;i+=2)
    {
       if(bl[Edge[i].to]!=bl[Edge[i^1].to]&&!Edge[i].dis)++ans;
       //cout<<Edge[i].to<<" ^^ "<<Edge[i^1].to<<"  "<<ans<<endl;  
    }
    printf("%d",ans);
    return 0;
}
int gg=haha();
int main()
{;}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值