清理雪道

滑雪场坐落在FJ省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。

输入格式:
输入文件的第一行包含一个整数n (2≤n≤100) – 代表滑雪场的地点的数量。接下来的n行,描述1 ~ n号地点出发的斜坡,第i行的第一个数为mi (0≤mi

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
#define N 201
#define M 50001
const int inf=2e9+1e8+4e7;
int ss,tt;
int n;
int cnt=1,to[M],val[M],C[M],L[M],R[M],ne[M],fir[N];
int ans;
queue<int>q;
bool inq[N];
int num,it;
int dis[N];
int m[N];
int sum;
int s,t;
void add(int x,int y,int w)
{
    to[++cnt]=y;C[cnt]=w;ne[cnt]=fir[x];fir[x]=cnt;
}
bool BFS(int s,int t)
{
    while(!q.empty()) q.pop();
    memset(dis,-1,sizeof(dis));memset(inq,0,sizeof(inq));
    q.push(s);dis[s]=0;inq[s]=1;
    while(!q.empty())
    {
        int ind=q.front();
        inq[ind]=0;q.pop();
        for(int i=fir[ind];i;i=ne[i])
        {
            if(!inq[to[i]]&&C[i]&&dis[to[i]]==-1)
            { 
                dis[to[i]]=dis[ind]+1;
                inq[to[i]]=1;
                q.push(to[i]);
            } 
        } 
    }
    return(dis[t]>=0);
}
int dfs(int now,int t,int fl)
{
    if(now==t||fl==0) return fl;
    int it=0;
    for(int i=fir[now];i;i=ne[i])
    {
        if(dis[to[i]]>dis[now])
        {
            int yu=dfs(to[i],t,min(fl,C[i]));
            if(yu)
            {
                it+=yu;
                C[i]-=yu;
                C[i^1]+=yu;
                fl-=yu;
            }
        }
    }
    return it;
}
int dinic(int s,int t)
{
    int fl=0;
    int ond=0;
    while(BFS(s,t))
    {
        ond=dfs(s,t,inf);
        if(!ond) return fl;
        fl+=ond;
    }
    return fl;
}
void prepare(void)
{
    scanf("%d",&n);
    ss=n+1;tt=n+2;s=tt+1;t=s+1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num);
//      if(num==0) {add(i,t,inf);add(t,i,0);}
//      add(s,i,inf);add(i,s,0);
        for(int j=1;j<=num;j++)
        {
            scanf("%d",&it);
            m[i]--;m[it]++;
            add(i,it,inf);
            add(it,i,0);
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(m[i]<0){add(i,tt,-m[i]);add(tt,i,0);}
        if(m[i]>0){add(ss,i,m[i]);add(i,ss,0);sum+=m[i];}
    }
}
int main(void)
{
    prepare();
    dinic(ss,tt);//去掉这句话是错的,玄学
    for(int i=1;i<=n;i++)
    {
        add(i,t,inf);add(t,i,0);
        add(s,i,inf);add(i,s,0);
    }
    add(t,s,inf);add(s,t,0);
    cout<<dinic(ss,tt);
}

Though I’m in the darkest days,it would be better!

liu_runda那篇适合入门
而这一篇则介绍了,我写的这个方法
http://blog.163.com/gc_chdch@126/blog/static/1722790522016329104433859/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值