最大流拆点——hdu2732,poj3436
一种很普遍的做法就是把一个带有容量的点拆成两个点,一个入点一个出点,链接两个点的边的权值为这个点的容量
hdu3732
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<string> #include<iostream> #define INF 1e9 using namespace std; const int maxn =1000+10; struct Edge { int from,to,cap,flow; Edge(){} Edge(int f,int t,int c,int fl):from(f),to(t),cap(c),flow(fl){} }; struct Dinic { int n,m,s,t; vector<Edge> edges; vector<int> G[maxn]; int cur[maxn]; int d[maxn]; bool vis[maxn]; void init(int n,int s,int t) { this->n=n, this->s=s, this->t=t; edges.clear(); for(int i=0;i<n;i++) G[i].clear(); } void AddEdge(int from,int to,int cap) { edges.push_back( Edge(from,to,cap,0) ); edges.push_back( Edge(to,from,0,0) ); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS() { queue<int> Q; Q.push(s); memset(vis,0,sizeof(vis)); d[s]=0; vis[s]=true; while(!Q.empty()) { int x=Q.front(); Q.pop(); for(int i=0;i<G[x].size();++i) { Edge& e=edges[G[x][i]]; if(!vis[e.to] && e.cap>e.flow) { d[e.to]=1+d[x]; vis[e.to]=true; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a) { if(x==t || a==0) return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();++i) { Edge& e=edges[G[x][i]]; if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0) { e.flow +=f; edges[G[x][i]^1].flow -=f; flow +=f; a-=f; if(a==0) break; } } return flow; } int max_flow() { int ans=0; while(BFS()) { memset(cur,0,sizeof(cur)); ans += DFS(s,INF); } return ans; } }DC; int main() { int T; scanf("%d",&T); for(int kase=1;kase<=T;++kase) { int n,m,d,src,dst; int sum=0;//蜥蜴数 scanf("%d%d",&n,&d); for(int i=1;i<=n;i++) { string s; cin>>s; if(i==1)//第一次 { m = s.size(); src=0, dst=2*n*m+1; DC.init(2*n*m+2,src,dst); } for(int j=0;j<s.size();++j)if(s[j]-'0'>0) { int id = (i-1)*m+j+1;//当前点编号 DC.AddEdge(id, id+n*m, s[j]-'0'); if(i<=d || i+d>n || j<d || j+d>=m)//当前格子能直接跳出棋盘 { DC.AddEdge(id+n*m,dst,INF); } else //不能直接跳出去 { for(int k=1;k<=n;k++) for(int h=0;h<m;h++) { int id2= (k-1)*m+h+1; if(id==id2) continue; if(abs(i-k)+abs(j-h)<= d) DC.AddEdge(id+n*m,id2,INF); } } } } for(int i=1;i<=n;++i) { string s; cin>>s; for(int j=0;j<s.size();++j) { int id = (i-1)*m+j+1;//当前点编号 if(s[j]=='L') { ++sum; DC.AddEdge(src,id,1); } } } int ans = sum-DC.max_flow(); if(ans==0) printf("Case #%d: no lizard was left behind.\n",kase); else if(ans==1) printf("Case #%d: 1 lizard was left behind.\n",kase); else printf("Case #%d: %d lizards were left behind.\n",kase,ans); } return 0; }
poj3436
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<cstring> #define Maxn 110 using namespace std; const int inf=0x3f3f3f3f; struct line{ int to,next,cap; }p[Maxn*Maxn*2]; int head[Maxn]; int q[Maxn]; int d[Maxn]; int cur[Maxn]; int tot; int src,t; int n,m; void addedge(int a,int b,int c){ p[tot].to=b; p[tot].next=head[a]; p[tot].cap=c; head[a]=tot++; } void insert(int a,int b,int c){ addedge(a,b,c); addedge(b,a,0); } bool bfs(){ memset(d,-1,sizeof d); int s=0,e=-1; q[++e]=src; d[src]=0; while(s<=e){ int u=q[s++]; for(int i=head[u];i!=-1;i=p[i].next){ int v=p[i].to; if(d[v]==-1&&p[i].cap){ d[v]=d[u]+1; q[++e]=v; } } } return d[t]!=-1; } int dfs(int u,int alpha){ if(u==t) return alpha; int w,used=0; for(int i=cur[u];i!=-1&&used<alpha;i=p[i].next){ int v=p[i].to; if(p[i].cap&&d[v]==d[u]+1){ w=dfs(v,min(alpha-used,p[i].cap)); used+=w; p[i].cap-=w; p[i^1].cap+=w; cur[u]=i; } } if(!used) d[u]=-1; return used; } int dinic(){ int ans=0; src=0,t=2*m+1; while(bfs()){ for(int i=src;i<=t;i++) cur[i]=head[i]; ans+=dfs(src,inf); } return ans; } int num[Maxn]; int input[Maxn][20],output[Maxn][20]; int vis[Maxn][Maxn]; bool check(int x,int y){ return x==y||y==2; } bool ck1(int d){ //没有1 for(int i=0;i<n;i++) if(input[d][i]==1) return false; return true; } bool ck2(int d){ //全1 for(int i=0;i<n;i++) if(output[d][i]!=1) return false; return true; } int main() { while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=m;i++){ scanf("%d",num+i); for(int j=0;j<n;j++) scanf("%d",&input[i][j]); for(int j=0;j<n;j++) scanf("%d",&output[i][j]); } memset(head,-1,sizeof head); memset(vis,0,sizeof vis); tot=0; for(int i=1;i<=m;i++) for(int j=1;j<=m;j++){ if(i==j) continue; bool flag=true; for(int k=0;k<n;k++) if(!check(output[i][k],input[j][k])){ flag=false; break; } if(flag){ insert(i+m,j,num[i]); vis[i+m][j]=1; } } for(int i=1;i<=m;i++){ insert(i,i+m,num[i]); //拆点 if(ck1(i)) insert(0,i,num[i]); if(ck2(i)) insert(i+m,2*m+1,num[i]); } printf("%d",dinic()); int cnt=0; for(int i=1;i<=m;i++){ for(int j=head[i+m];j!=-1;j=p[j].next) if(vis[i+m][p[j].to]&&p[j].cap<num[i]) cnt++; } printf(" %d\n",cnt); for(int i=1;i<=m;i++){ for(int j=head[i+m];j!=-1;j=p[j].next) if(vis[i+m][p[j].to]&&p[j].cap<num[i]){ printf("%d %d %d\n",i,p[j].to,num[i]-p[j].cap); } } } return 0; }