poj2125 网络流

【题意】

给出一个有向图,定义两种操作:w+(i)删掉i点的所有入边w-(i)删掉i点的所有出边,每种

操作都有对应的花费,问删掉所有边的最小花费。

【解答】

我基于的想法是对于每个点,分拆成ai和bi,ai表示入度,bi表示出度。根据点度数的条件

建图,后来我发现我的建图方法和人家的最小点覆盖的思路是一样的!我猛然发现最小点

覆盖的思路更好理解。同时,我还看到了人家的有趣的分析:

画出邻接矩阵后,模型就变成了,有两种武器,分别可以覆盖一行或者一列,就变成了

poj3308一样。(值得借鉴的思路)

#include <iostream>
using namespace std;

const int oo=99999999,maxn=500,maxm=50000;
struct edge
{
       int x,y,f,next,op;
}e[maxm];
int h[maxn],d[maxn],p[maxn],now[maxn],num[maxn];
bool v[maxn];
int n,m,s,t,tot;

void ins(int x,int y,int f)
{
     e[++tot].x=x;e[tot].y=y;
     e[tot].next=h[x];e[tot].f=f;
     h[x]=tot;
     e[++tot].x=y;e[tot].y=x;
     e[tot].next=h[y];e[tot].f=0;
     h[y]=tot;
     e[tot].op=tot-1;e[tot-1].op=tot;
}

int isap()
{
    int flow=0,aug=oo,u,v,tmp,i,j,ff;
    for (i=0;i<=t;i++)
    {
        d[i]=0;p[i]=-1;
        num[i]=0;now[i]=h[i];
    }
    num[0]=t+1;u=s;
    while (d[s]<t+1)
    {
          for (ff=0,i=now[u];i;i=e[i].next)
          {
              v=e[i].y;
              if (e[i].f && d[u]==d[v]+1)
              {
                 ff=1;
                 if (e[i].f<aug) aug=e[i].f;
                 p[v]=i;now[u]=i;
                 u=v;
                 if (u==t)
                 {
                    flow+=aug;
                    while (u!=s)
                    {
                          j=p[u];
                          e[j].f-=aug;
                          e[e[j].op].f+=aug;
                          u=e[j].x;
                    }
                    aug=oo;
                 }
                 break;
              }
          }
          if (ff) continue;
          num[d[u]]--;
          if (!num[d[u]]) return flow;
          tmp=t+1;
          for (i=h[u];i;i=e[i].next)
          {
              v=e[i].y;
              if (e[i].f && d[v]<tmp) 
              {
                 tmp=d[v];now[u]=i;
              }
          }
          d[u]=tmp+1;
          num[d[u]]++;
          if (u!=s) u=e[p[u]].x;
    }
    return flow;
}

void dfs(int x)
{
     v[x]=true;
     for (int i=h[x];i;i=e[i].next)
     if (e[i].f && !v[e[i].y])
        dfs(e[i].y);
}

int main()
{
    freopen("pin.txt","r",stdin);
    freopen("pou.txt","w",stdout);
    int i,x,y,ans;
    cin >> n >> m;
    s=0;t=n+n+1;
    for (i=1;i<=n;i++)
    {
        cin >> x;
        ins(i+n,t,x);
    }
    for (i=1;i<=n;i++)
    {
        cin >> x;
        ins(s,i,x);
    }
    for (i=0;i<m;i++)
    {
        cin >> x >> y;
        ins(x,y+n,oo);
    }
    cout << isap() << endl;
    memset(v,0,sizeof(v));
    dfs(s);
    ans=0;
    for (i=1;i<=n;i++)
        ans+=(!v[i])+(v[i+n]);
    cout << ans << endl;
    for (i=1;i<=n;i++)
    {
        if (!v[i]) cout << i << " -\n";
        if (v[i+n]) cout << i << " +\n";
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值