网络流:最大流

http://poj.org/problem?id=3281

题意:

多种饮料和食物,多种牛,每种牛可以在它喜欢的饮料和食物中选一种。三者都只能用一次,求最大满足牛的数量。

解析:

最大流构造:

  1. 饮料和食物只能用一次,那么连源点到饮料,食物到汇点,容量1
  2. 饮料和食物需要牛连接,饮料到牛,牛到食物
  3. 牛只能用一次,牛拆成两个点,之间容量为1
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;

const int inf=0x3f3f3f3f;
const int N=550,M=40001;

int n,f,D;

int head[N],nex[M],to[M],val[M],now;
void add(int a,int b,int v){
    to[++now]=b;val[now]=v;nex[now]=head[a];head[a]=now;
    to[++now]=a;val[now]=0;nex[now]=head[b];head[b]=now;
}

//*********************

int sp,ep,d[N];

int bfs(){
    queue<int>Q;
    memset(d,-1,sizeof(d));
    d[sp]=0;
    Q.push(sp);
    while(!Q.empty()){
        int p=Q.front();Q.pop();
        for(int i=head[p];~i;i=nex[i]){
            int u=to[i];
            if(d[u]==-1&&val[i]>0){
                d[u]=d[p]+1;
                Q.push(u);
            }
        }
    }
    return d[ep]!=-1;
}

int dfs(int p,int v){
    int r=0;
    if(p==ep)return v;
    for(int i=head[p];(~i)&&r<v;i=nex[i]){
        int u=to[i];
        if(val[i]>0&&d[u]==d[p]+1){
            int x=dfs(u,min(val[i],v-r));
            r+=x;
            val[i]-=x;
            val[i^1]+=x;
        }
    }
    if(!r)d[p]=-2;
    return r;
}

int dinic(){
    int ans=0,t;
    while(bfs()){
        while(t=dfs(sp,inf))ans+=t;
    }
    return ans;
}

//***********************

void init(){
    now=-1;//要求第一条边为0
    memset(head,-1,sizeof(head));
}

int main(){
    init();
    scanf("%d%d%d",&n,&f,&D);
    for(int i=1;i<=f;i++)add(0,i,1);
    for(int i=1;i<=D;i++)add(i+300,401,1);
    for(int i=1;i<=n;i++){
        add(i+100,i+200,1);
        int nf,nd;scanf("%d%d",&nf,&nd);
        for(int j=1,tmp;j<=nf;j++)scanf("%d",&tmp),add(tmp,i+100,1);
        for(int j=1,tmp;j<=nd;j++)scanf("%d",&tmp),add(i+200,tmp+300,1);
    }
    sp=0,ep=401;
    int ans=dinic();
    printf("%d\n",ans);
}

http://acm.hdu.edu.cn/showproblem.php?pid=2732

题意:

n*m地图上,有很多柱子,已经很多蜥蜴,蜥蜴可以跳到曼哈顿距离小于等于d的柱子上。柱子有一个耐久度,当一只蜥蜴从这个柱子上跳走时,耐久度-1,为0时不能有蜥蜴跳到上面。

蜥蜴跳出地图则获救,问最少还有几只蜥蜴留下。

解析:

首先是源点到蜥蜴健一条1的,然后要控制每个点走过的数量,点拆成两个点控制。点和点之间建,点到地图外(汇点)建。

//hdu 2732 最大流

#include<stdio.h>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;

const int inf=0x3f3f3f3f;
const int N=1001,M=40001;

int head[N],nex[M],to[M],val[M],now;
void add(int a,int b,int v){
    to[++now]=b;val[now]=v;nex[now]=head[a];head[a]=now;
    to[++now]=a;val[now]=0;nex[now]=head[b];head[b]=now;
}

//*********************

int sp,ep,d[N];

int bfs(){
    queue<int>Q;
    memset(d,-1,sizeof(d));
    d[sp]=0;
    Q.push(sp);
    while(!Q.empty()){
        int p=Q.front();Q.pop();
        for(int i=head[p];~i;i=nex[i]){
            int u=to[i];
            if(d[u]==-1&&val[i]>0){
                d[u]=d[p]+1;
                Q.push(u);
            }
        }
    }
    return d[ep]!=-1;
}

int dfs(int p,int v){
    int r=0;
    if(p==ep)return v;
    for(int i=head[p];(~i)&&r<v;i=nex[i]){
        int u=to[i];
        if(val[i]>0&&d[u]==d[p]+1){
            int x=dfs(u,min(val[i],v-r));
            r+=x;
            val[i]-=x;
            val[i^1]+=x;
        }
    }
    if(!r)d[p]=-2;
    return r;
}

int dinic(){
    int ans=0,t;
    while(bfs()){
        while(t=dfs(sp,inf))ans+=t;
    }
    return ans;
}

//***********************

void init(){
    now=-1;//要求第一条边为0
    memset(head,-1,sizeof(head));
}

char Mp[21][21];
int V[21][21];

int id1(int i,int j){
    return (i-1)*21+j;
}
int id2(int i,int j){
    return 450+(i-1)*21+j;
}

int main(){int t;int ca=0;cin>>t;while(t--){
    sp=0,ep=450;
    init();
    int n,m,d;
    scanf("%d%d",&n,&d);
    for(int i=1;i<=n;i++)scanf("%s",Mp[i]+1);
    m=strlen(Mp[1]+1);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            V[i][j]=Mp[i][j]-'0';
            if(V[i][j])add(id1(i,j),id2(i,j),V[i][j]);
        }
    }
    int All=0;
    for(int i=1;i<=n;i++)scanf("%s",Mp[i]+1);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(Mp[i][j]=='L'){
                All++;
                add(0,id1(i,j),1);
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!V[i][j])continue;
            for(int k=-d;k<=d;k++){
                for(int h=abs(k)-d;h<=d-abs(k);h++){
                    int x=i+k,y=j+h;
                    if(x<=0||y<=0||x>n||y>m)add(id2(i,j),450,V[i][j]);
                    else if(V[x][y]){
                        add(id2(i,j),id1(x,y),V[i][j]);
                    }
                }
            }
        }
    }
    int ans=dinic();
    if(ans==All)printf("Case #%d: no lizard was left behind.\n",++ca);
    else if(All-ans==1)printf("Case #%d: %d lizard was left behind.\n",++ca,1);
    else printf("Case #%d: %d lizards were left behind.\n",++ca,All-ans);
}}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/86582651