今天的内容主要是网络流建模以及二分图(二分图暂缺)
例题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同意,禁止转载,侵权者必究。