SOJ 3134: windy和水星 -- 水星交通

挺无聊的一道网络流

不过有一个挺有特色的地方是要枚举汇点,觉得挺好玩的就记录下来吧


题意:有N个点,每两个点间都有一条双向边,问使这些点中至少有两个点不连通所需要破坏的边的最小权值

题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=3134


取任意点为S点,若u,v两点不连通,则u,v中至少有一个与S也不连通。

因为题目中均为双向边,若u,v均与s连通,那么由路径u->s->v可知u,v也应该是连通的

所以显然S点是可以任取的,但是T点是需要枚举的。

那么就枚举T点依次求最小割,取最小值

PS:这道题写的比较早,那时候我的sap模板还很挫。。还加了dinic优化的。。后来发现稠密图用dinic实在是慢,参考了lieyan大神的代码后就去掉了bfs预处理。。


#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7f7f7f7f
using namespace std;
int p[105],d[105],gap[105],cap[105][105],f[105][105],S,T;

void bfs(int n)
{
    int u,v;
    memset(d,-1,sizeof(d));
    memset(gap,0,sizeof(gap));
    queue<int>dd;
    dd.push(T);
    d[T]=0;gap[0]=1;
    while(!dd.empty())
    {
      u=dd.front();dd.pop();
      for(v=1;v<=n;v++)
      if((cap[v][u]>f[v][u])&&(d[v]==-1)) 
      {                 
      d[v]=d[u]+1;
      gap[d[v]]++;
      dd.push(v);                   
      }      
    } 
}

int sap(int n)
{
int v,u,a,mind,ans;
bfs(n);
u=S;ans=0;
memset(p,-1,sizeof(p));
while(d[S]<n)
{
for(v=1;v<=n;v++)if(cap[u][v]>f[u][v]&&d[u]==d[v]+1 ) break;
if(v<=n)
{
p[v]=u;u=v;    
if(v==T)
{
int a=INF;
for(v=T;v!=S;v=p[v])a=a<(cap[p[v]][v]-f[p[v]][v])?a:(cap[p[v]][v]-f[p[v]][v]);
for(v=T;v!=S;v=p[v])
    {
    f[p[v]][v]+=a;
    f[v][p[v]]-=a;    
    }
ans+=a; 
u=S;             
}
}
else
{
    int mind=n;
    for(v=1;v<=n;v++)if(cap[u][v]>f[u][v])mind=mind<d[v]+1?mind:d[v]+1;
    --gap[d[u]];
    if(gap[d[u]]==0)return ans; 
    ++gap[mind];  
    d[u]= mind; 
    if(u!=S) u=p[u]; 
}
}
return ans;
}

int main()
{
    int n,i,j,ans,x;
    while(scanf("%d",&n)!=EOF)
    {
    for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)
    scanf("%d",&cap[i][j]);
    ans=INF;
    S=1;
    for(T=2;T<=n;T++)
    {
    memset(f,0,sizeof(f));
    x=sap(n);
    ans=ans<x?ans:x;
    }
    printf("%d\n",ans);  
    }                     
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值