码迷,mamicode.com
首页 > 其他好文 > 详细

hdu4289城市与歹徒 网络流

时间:2020-02-12 22:14:52      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:左右   continue   std   cstring   include   一个   pop   for   code   

  题目大意就是要从歹徒要从s点运送货物到t点,警察在一些城市拦截,在每一个城市拦截都有一定的花费,问最小花费是多少可以拦截住歹徒。

  呐,在某些点设置障碍,使得整张图不能在联通,我们知道一个类似的问题:割断某些点使得图不能再联通——最小割问题,那么把这些点拆了,点权变为边权,不就是最小割问题了么,我们知道最小割等于最大流,所以这就是一个拆点+网络流的问题。

  代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=2100,maxm=50005;
const int inf=2147483647;
int n,m; 
int S,T;
int x,y;
struct zhw{
    int to,last,val;
}tu[maxm<<2];
int tot,head[maxn];
void add(int x,int y,int v)
{
    tot++,tu[tot].last=head[x],head[x]=tot,tu[tot].to=y,tu[tot].val=v;
    tot++,tu[tot].last=head[y],head[y]=tot,tu[tot].to=x,tu[tot].val=0;
}
int ans;
bool vis[maxn];
int dis[maxn];
queue<int>q;
bool bfs()
{
    memset(vis,0,sizeof(vis));
    memset(dis,0,sizeof(dis));
    q.push(S);vis[S]=1;dis[S]=1;
    while(!q.empty())
    {
        int k=q.front();q.pop();
        for(int i=head[k];i;i=tu[i].last)
        {
            if(!vis[tu[i].to]&&tu[i].val)
            {
                vis[tu[i].to]=1;
                dis[tu[i].to]=dis[k]+1;
                q.push(tu[i].to);
            }
        }
    }
    return vis[T];
}
int m_flow(int now,int lim)
{
    if(!lim||now==T)return lim;
    int flow=0,f;
    for(int i=head[now];i;i=tu[i].last)
    {
        if(dis[tu[i].to]==dis[now]+1&&tu[i].val>0)
        {
            f=m_flow(tu[i].to,min(lim,tu[i].val));
            if(!f)continue;
            flow+=f,lim-=f;
            tu[i].val-=f,tu[i^1].val+=f; 
            if(!lim)break;
        }
    }
    if(!flow)dis[now]=-1;
    return flow;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        scanf("%d%d",&x,&y);
        S=x,T=y;
        tot=1,memset(head,0,sizeof(head));
        add(S,x,inf),add(y+n,T,inf);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&x);
            add(i,i+n,x);//这就是拆点的部分,把一个点拆成左右两部分,这个点的入边必然是从左边入,出边必然是从右边出,边权是原来的点权
        }
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d",&x,&y);
            add(x+n,y,inf);//如上,既然是自己约束自己,必然是左边进右边出,路是双向边,没有约束,所以流量是正无穷
            add(y+n,x,inf);
        }
        ans=0;
        T=T+n;//这里一定要注意,最后肯定是要跑到右边的T才可以呀,我一开始就是这里错了
        while(bfs())
        {
            ans+=m_flow(S,inf);
        }
        printf("%d\n",ans);
    }
    return 0;
} 

 

hdu4289城市与歹徒 网络流

标签:左右   continue   std   cstring   include   一个   pop   for   code   

原文地址:https://www.cnblogs.com/yuelian/p/12301079.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!