COGS血帆海盗

对于已经增广后的图,会出现一些反向边,首先跑一边最大流,只有对于被增广的路才有可能成为答案,考虑每一条被曾广的路,如果他在残留网络中两个端点在同一个强连通分量里,必然有其他的路径可以代替这条边,比如图中1 2 3 4 构成一个环3-》2-》1-》4-》3,3-》2可以替代原来的1》2,所以只有那些被增广后,起点终点不在一个强连通分量里,才对答案有贡献

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define N 100005 
using namespace std;
int n,m,cnt=0,k=0;
struct edge
{
    int to,ne,w;  
}b[N*4];
int head[N];
bool v[N*2];
void add(int u,int v,int w)
{
     b[k].to=v;b[k].ne=head[u];b[k].w=w;head[u]=k;
     k++;
}
int dfn[N],low[N],ti=0,s[N],num=0,be[N],he=0;
bool vis[N];
void read()
{ 
     int x,y;
     scanf("%d%d",&n,&m);
     cnt=n+1;
     for(int i=1;i<=n/2;i++){
       add(0,i,1); add(i,0,0);
     }
     for(int i=n/2+1;i<=n;i++){
       add(i,cnt,1); add(cnt,i,0);
     } 
     for(int i=1;i<=m;i++){
       scanf("%d%d",&x,&y);
       add(x,y,1); add(y,x,0);
     }
   
}
int d[N];
bool bfs()
{
     memset(d,0,sizeof(d));
     queue<int> q;
     q.push(0);d[0]=1;
     while(!q.empty())
     {
           int z=q.front();q.pop();
           for(int i=head[z];i!=-1;i=b[i].ne)
           if(b[i].w&&!d[b[i].to])
           {
              d[b[i].to]=d[z]+1;
              q.push(b[i].to);
              if(b[i].to==cnt) return 1;                   
           }           
     }
     return 0;
}
int dfs(int now,int f)
{
    if(now==cnt) return f;
    int tmp=f,k;
    for(int i=head[now];i!=-1;i=b[i].ne)
    if(b[i].w&&tmp&&d[b[i].to]==d[now]+1){
         k=dfs(b[i].to,min(b[i].w,tmp));
         if(!k) {d[b[i].to]=0;continue;}
         b[i].w-=k;b[i^1].w+=k;tmp-=k; 
    }
    return f-tmp;
}

void Targan(int x)
{
     dfn[x]=low[x]=++ti;
     vis[x]=1; s[++he]=x;
     for(int i=head[x];i!=-1;i=b[i].ne)
     if(b[i].w){
         int to=b[i].to;
         if(dfn[to]==-1){
            Targan(to);
            low[x]=min(low[x],low[to]);
         }
         else if(vis[to]==1) low[x]=min(low[x],dfn[to]);
     }
     int z;
     if(dfn[x]==low[x]){
         num++;
         while(1){
            z=s[he--];
            be[z]=num;
            vis[z]=0;
            if(z==x) break; 
         }
     }
}
int ans=0;
void judge()
{
     
      for(int i=1;i<=n;i++)
        if(dfn[i]==-1){
            Targan(i);
      }
      for(int i=1;i<=n/2;i++)
        for(int j=head[i];j!=-1;j=b[j].ne)
        if(b[j].to>i&&b[j].to!=cnt&&b[j].w==0&&be[i]==be[b[j].to]) ans--; 
}
int main()
{
   // freopen("in.txt","r",stdin);
    freopen("bloodsail.in","r",stdin);
   freopen("bloodsail.out","w",stdout);
    memset(head,-1,sizeof(head));
    memset(dfn,-1,sizeof(dfn));
    read(); 
    while(bfs()==1) ans+=dfs(0,0x7fffffff);
    judge();    
    printf("%d",ans);
  //  while(1);
    return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值