今天的内容主要是网络流建模以及二分图(二分图暂缺)

例题1:dining(poj3281)

把牛“掰"成两个点就好了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector> 
#include<queue>
using namespace std;
inline int read(){
    int t=1,num=0;
    char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();}
    while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();}
    return num*t;
}
const int INF=10000010;
struct edge{
    int to;int c;int rev;
};
vector<edge> g[410];
int iter[410],level[410];
inline void add(int f,int t,int c){
    g[f].push_back((edge){t,c,g[t].size()});
    g[t].push_back((edge){f,0,g[f].size()-1});
}
void bfs(int s){
    memset(level,0,sizeof(level));
    queue<int>q;
    level[s]=1;
    q.push(s);
    while(!q.empty()){
        int v=q.front();q.pop();
        for(int i=0;i<g[v].size();i++){
            edge &e=g[v][i];
            if(e.c>0&&level[e.to]==0){
                level[e.to]=level[v]+1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f){
    if(v==t) return f;
    for(int &i=iter[v];i<g[v].size();i++){
        edge &e=g[v][i];
        if(e.c>0&&level[v]+1==level[e.to]){
            int d=dfs(e.to,t,min(f,e.c));
            if(d>0){
                e.c-=d;
                g[e.to][e.rev].c+=d;
                return d;
            }
        }
    }
    return 0;
}
int flow(int s,int t){
    int flow=0;
    while(1){
        bfs(s);
        if(level[t]==0) return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0)flow+=f;
    }
}
int n,f,d;
int main()
{
    n=read();f=read();d=read();
    int s=0,t=f+d+n+n+1;
    for(int i=1;i<=f;i++)add(s,i,1);
    for(int i=1;i<=d;i++)add(f+n+n+i,t,1);
    for(int i=1;i<=n;i++){
        int F,D,x;F=read();D=read();
        add(f+i,f+n+i,1);
        for(int j=1;j<=F;j++)x=read(),add(x,f+i,1);
        for(int j=1;j<=D;j++)x=read(),add(f+n+i,f+n+n+x,1);
    }
    printf("%d",flow(s,t));
    return 0;
}

 

例题2:文理分科(BZOJ3294)

这题是最小割

s向每个学生连权为art[i][j]边,每个学生再向t连权为science[i][j]边。

割断连向t的边说明选文,反之选理。

根据题意的另一个要求:如果每位学生的上下左右都同该学生选同一种会有额外的利润

以文为例:

建立一个虚点

将s向这个虚点连权为same_art的边

再由虚点连向该 学生以及其上下左右的学生 一条边,边权为INF

这样如果五个人中有一个选理就要割断s到虚点的边

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector> 
#include<queue>
#define For(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
inline int read(){
    int t=1,num=0;
    char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();}
    while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+c-'0';c=getchar();}
    return num*t;
}
const int INF=10000010,mn=30011;
struct edge{
    int to;int c;int rev;
};
vector<edge> g[mn];
int iter[mn],level[mn];
void add(int f,int t,int c){
    g[f].push_back((edge){t,c,g[t].size()});
    g[t].push_back((edge){f,0,g[f].size()-1});
}
void bfs(int s){
    memset(level,0,sizeof(level));
    queue<int>q;
    level[s]=1;
    q.push(s);
    while(!q.empty()){
        int v=q.front();q.pop();
        for(int i=0;i<g[v].size();i++){
            edge &e=g[v][i];
            if(e.c>0&&level[e.to]==0){
                level[e.to]=level[v]+1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f){
    if(v==t) return f;
    for(int &i=iter[v];i<g[v].size();i++){
        edge &e=g[v][i];
        if(e.c>0&&level[v]+1==level[e.to]){
            int d=dfs(e.to,t,min(f,e.c));
            if(d>0){
                e.c-=d;
                g[e.to][e.rev].c+=d;
                return d;
            }
        }
    }
    return 0;
}
int flow(int s,int t){
    int flow=0;
    while(1){
        bfs(s);
        if(level[t]==0) return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0)flow+=f;
    }
}
int a[10001],s[10001],sa[10001],ss[10001];
int main()
{
    int S=0,T=30010,n,m,tot=0;n=read();m=read();int N=n*m;
    For(i,1,N)a[i]=read(),tot+=a[i];
    For(i,1,N)s[i]=read(),tot+=s[i];
    For(i,1,N)sa[i]=read(),tot+=sa[i];
    For(i,1,N)ss[i]=read(),tot+=ss[i];
    For(i,1,N)add(S,i,a[i]),add(i,T,s[i]);
    For(i,1,N){
        add(S,N+i,sa[i]);add(N+i,i,INF);
        add(i,N+N+i,INF);add(N+N+i,T,ss[i]);
        if(i%m)add(N+i,i+1,INF),add(i+1,N+N+i,INF);
        if(i%m!=1)add(N+i,i-1,INF),add(i-1,N+N+i,INF);
        if(i+m<=N)add(N+i,i+m,INF),add(i+m,N+N+i,INF);
        if(i-m>0)add(N+i,i-m,INF),add(i-m,N+N+i,INF);
    }
    printf("%d",tot-flow(S,T));
    return 0;
}

例题3:QQ农场(9018_1974)

本题与上题有些相似

请根据上题思路自己思考

想想为什么这么做

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector> 
#include<queue>
using namespace std;
inline int read(){
    int t=1,num=0;
    char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();}
    while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+c-'0';c=getchar();}
    return num*t;
}
const int INF=10000010,mn=40011;
struct edge{
    int to;int c;int rev;
};
vector<edge> g[mn];
int iter[mn],level[mn];
void add(int f,int t,int c){
    g[f].push_back((edge){t,c,g[t].size()});
    g[t].push_back((edge){f,0,g[f].size()-1});
}
void bfs(int s){
    memset(level,0,sizeof(level));
    queue<int>q;
    level[s]=1;
    q.push(s);
    while(!q.empty()){
        int v=q.front();q.pop();
        for(int i=0;i<g[v].size();i++){
            edge &e=g[v][i];
            if(e.c>0&&level[e.to]==0){
                level[e.to]=level[v]+1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f){
    if(v==t) return f;
    for(int &i=iter[v];i<g[v].size();i++){
        edge &e=g[v][i];
        if(e.c>0&&level[v]+1==level[e.to]){
            int d=dfs(e.to,t,min(f,e.c));
            if(d>0){
                e.c-=d;
                g[e.to][e.rev].c+=d;
                return d;
            }
        }
    }
    return 0;
}
int flow(int s,int t){
    int flow=0;
    while(1){
        bfs(s);
        if(level[t]==0) return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0)flow+=f;
    }
}
int n,a[40100],tot=0;
int main()
{
    n=read();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int x=read();tot+=x;
            if(i%2&&j%2||(i%2==0&&j%2==0))add(0,(i-1)*n+j,x),a[(i-1)*n+j]=1;
            else add((i-1)*n+j,n*n+1,x);
        }
    }
    for(int i=1;i<=n*n;i++){
        if(!a[i])continue;
        if(i%n)add(i,i+1,INF);
        if(i%n!=1)add(i,i-1,INF);
        if(i+n<=n*n)add(i,i+n,INF);
        if(i-n>0)add(i,i-n,INF);
    }
    printf("%d",tot-flow(0,n*n+1));
    return 0;
}

本文由Yzyet编写,网址为www.cnblogs.com/Yzyet。非Yzyet同意,禁止转载,侵权者必究。

posted on 2017-07-04 21:53  Yzyet  阅读(136)  评论(0编辑  收藏  举报