P2756 飞行员配对方案问题
简单二分图匹配
#include<bits/stdc++.h> using namespace std; #define pb push_back const int N=1e3+5; int gp[N][N],match[N],vis[N]; int n,m; bool findpath(int u){ for(int i=m+1;i<=n+m;i++){ if(gp[u][i]&&!vis[i]){ vis[i]=1; if(!match[i]||findpath(match[i])){ match[i]=u; return 1; } } } return 0; } void init(){ memset(gp,0,sizeof gp); memset(match,0,sizeof match); } int main(){ init(); scanf("%d %d",&m,&n); int u,v; while(~scanf("%d %d",&u,&v)){ if(u+v<0)break; gp[u][v]=1; } vector<int>ans; for(int i=1;i<=m;i++){ memset(vis,0,sizeof vis); if(findpath(i))ans.pb(i); } for(int i=m+1;i<=n+m;i++){ if(match[i])match[ match[i] ]=i; } cout<<ans.size()<<endl; for(int i=0;i<ans.size();i++){ printf("%d %d ",ans[i],match[ ans[i] ]); } // system("pause"); return 0; }
P4015 运输问题
easy
#include<bits/stdc++.h> using namespace std; const int N=1e4+50; const int inf=0x3f3f3f3f; int a[200],b[200],c[200][200]; int n,m,S,T; int mincost; struct Dinic{ int head[N],dis[N],pre[N],flow[N],last[N]; bool inq[N]; int ecnt; struct edge{ int v,w,flow,next; }e[N*10]; void init(){ memset(head,-1,sizeof head); ecnt = 0; } void addedge(int u,int v,int w,int flow){ e[ecnt].v=v;e[ecnt].w=w;e[ecnt].flow=flow;e[ecnt].next=head[u];head[u]=ecnt++; } bool spfa(){ memset(dis,inf,sizeof dis); memset(flow,inf,sizeof flow); memset(inq,0,sizeof inq); queue<int>Q; Q.push(S);inq[S]=1;dis[S]=0;pre[T]=-1; while(!Q.empty()){ int u=Q.front();Q.pop();inq[u]=0; for(int i=head[u];~i;i=e[i].next){ int v=e[i].v,w=e[i].w; if(e[i].flow>0&&dis[v]>dis[u]+w){ dis[v]=dis[u]+w;pre[v]=u;last[v]=i; flow[v]=min(flow[u],e[i].flow); if(!inq[v]){ Q.push(v);inq[v]=1; } } } } return pre[T]!=-1; } void MCMF(){ mincost=0; while(spfa()){ int cur=T; mincost+=flow[T]*dis[T]; while(cur!=S){ e[last[cur]].flow-=flow[T]; e[last[cur]^1].flow+=flow[T]; cur=pre[cur]; } } } }dinic; void init_add(int t){ for(int i=1;i<=m;i++){ dinic.addedge(S,i,0,a[i]); dinic.addedge(i,S,0,0); } for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ dinic.addedge(i,j+m,t*c[i][j],inf); dinic.addedge(j+m,i,-c[i][j]*t,0); } } for(int i=1;i<=n;i++){ dinic.addedge(i+m,T,0,b[i]); dinic.addedge(T,i+m,0,0); } } int main(){ scanf("%d %d",&m,&n); S=0,T=10005; for(int i=1;i<=m;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)scanf("%d",&b[i]); for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ scanf("%d",&c[i][j]); } } dinic.init(); init_add(1); dinic.MCMF(); printf("%d ",mincost); dinic.init(); init_add(-1); dinic.MCMF(); printf("%d ",-mincost); // system("pause"); return 0; }
P2764 最小路径覆盖问题
考虑最初有n个路径穿过n个点,那么如果两两之间有边,就可以把路径合并,做法就是把每个点拆成两个点,如果有边就连一下,表示联通。
跑一遍最大流,实际上就是合并尽可能多的路径。
输出路径:把一条路径的点合并到一个并查集里,然后起点标记为父结点,递归输出。
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; const int inf=0x3f3f3f3f; struct edge{int v,next;}e[N*10]; int n,m,S,T; struct Dinic{ int head[N],dep[N]; int ecnt; struct edge{ int v,flow,next; }e[N*10]; void init(){ memset(head, -1, sizeof head); ecnt = 0; } void addedge(int u, int v, int flow) { e[ecnt].v=v;e[ecnt].flow=flow;e[ecnt].next=head[u];head[u]=ecnt++; e[ecnt].v=u;e[ecnt].flow=0;e[ecnt].next=head[v];head[v]=ecnt++; } bool BFS(){//分层图找增广路 memset(dep,0,sizeof dep); queue<int>Q; Q.push(S);dep[S]=1; while(!Q.empty()){ int u=Q.front();Q.pop(); for(int i=head[u];~i;i=e[i].next){ if(e[i].flow&&!dep[e[i].v]){ dep[e[i].v]=dep[u]+1; Q.push(e[i].v); } } } return dep[T]; } int DFS(int u, int f){//推进新流 if(u==T||f==0)return f; int w,used=0; for(int i=head[u];~i;i=e[i].next){ if(e[i].flow&&dep[e[i].v]==dep[u]+1){ w=DFS(e[i].v,min(f,e[i].flow));//多路增广 e[i].flow-=w;e[i^1].flow+=w; used+=w;f-=w; } } if(!used)dep[u]=-1;//炸点优化 return used; } int maxflow() { int ans=0; while(BFS()){ ans+=DFS(S,inf); } return ans; } int fa[N]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} void build(int x,int y){int dx=find(x),dy=find(y);if(dx!=dy)fa[dx]=dy;} void print(int u){ printf("%d ",u); for(int i=head[u];~i;i=e[i].next){ if(e[i].flow==0&&e[i].v>n){ print(e[i].v-n); } } } void work(){ for(int i=1;i<=n;i++)fa[i]=i; int ans=maxflow(); for(int u=1;u<=n;u++){ for(int i=head[u];~i;i=e[i].next){ // if(e[i].v==T)continue; if(e[i].flow==0&&e[i].v>n){ build(e[i].v-n,u); } } } for(int cur=1;cur<=n;cur++){ if(find(cur)==cur){print(cur);puts("");} } printf("%d ",n-ans); } }dinic; int main(){ scanf("%d %d",&n,&m); dinic.init(); S=0,T=2*n+50; int u,v; while(m--){ scanf("%d %d",&u,&v); dinic.addedge(u,v+n,1); } for(int i=1;i<=n;i++){ dinic.addedge(i+n,T,1); } for(int i=1;i<=n;i++){ dinic.addedge(S,i,1); } dinic.work(); // system("pausea"); return 0; }