标签:
题意:把K个超级计算机从S运到T,其中有m条双向隧道,隧道在用的时候只能从一边到另外一边,要你求出多少天能够完成任务,并把每一天的移动路径的边的两个节点输出
思路:ORZ,这样都能想到网络流,表示太弱!看了白书之后才知道,原来可以进行拆点!
每天,我们可以假设每个点是ui,那么我们可以找到存在隧道的点ui与vi,那么ui可以到达v(i+1),容量为1,vi可以到达u(i+1)容量为1,那么我们每天可以在前一天最大流的基础上再今夕增广,知道求出k
AC代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<vector> using namespace std; #define ll long long #define maxn 2020 const int INF=0x3f3f3f3f; struct Edge { int from,to,cap,flow; }; struct ISAP { int n,m,s,t; vector<Edge>edges; vector<int>g[maxn]; int vis[maxn]; int d[maxn],cur[maxn]; int p[maxn],num[maxn]; void init() { edges.clear(); } void ClearEdge(int bn,int n) { this->n = n ; for(int i=bn;i<n;i++)g[i].clear(); } void Clearflow() { for(int i=0;i<n;i++) edges[i].flow=0; } 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() { memset(vis,0,sizeof(vis)); queue<int>q; q.push(t); vis[t]=1; d[t]=0; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=0;i<g[x].size();i++) { Edge& e=edges[g[x][i]^1]; if(!vis[e.from]&&e.cap>e.flow) { vis[e.from]=true; d[e.from]=d[x]+1; q.push(e.from); } } } return vis[s]; } int Augment() { int x=t,a=INF; while(x!=s) { Edge& e=edges[p[x]]; a=min(a,e.cap-e.flow); x=edges[p[x]].from; } x=t; while(x!=s) { edges[p[x]].flow+=a; edges[p[x]^1].flow-=a; x=edges[p[x]].from; } return a; } int Maxflow(int s,int t,int limit) { this->s=s; this->t=t; int flow=0; BFS(); memset(num,0,sizeof(num)); for(int i=0;i<n;i++)num[d[i]]++; int x=s; memset(cur,0,sizeof(cur)); while(d[s]<n) { if(x==t) { flow+=Augment(); if(flow>=limit)return flow; x=s; } int ok=0; for(int i=cur[x];i<g[x].size();i++) { Edge& e=edges[g[x][i]]; if(e.cap>e.flow&&d[x]==d[e.to]+1) { ok=1; p[e.to]=g[x][i]; cur[x]=i; x=e.to; break; } } if(!ok) { int m=n-1; for(int i=0;i<g[x].size();i++) { Edge& e=edges[g[x][i]]; if(e.cap>e.flow)m=min(m,d[e.to]); } if(--num[d[x]]==0)break; num[d[x]=m+1]++; cur[x]=0; if(x!=s)x=edges[p[x]].from; } } return flow; } void Reduce() { for(int i=0;i<edges.size();i++) edges[i].cap-=edges[i].flow; } vector<int> Mincut() { vector<int> ans; BFS(); for(int i=0;i<edges.size();i++) { Edge e=edges[i]; if(!vis[e.from]&&vis[e.to]&&e.cap>0)ans.push_back(i); } return ans; } }sol; vector<pair<int,int> >path,ans; int main() { int n,m,k,s,t; while(scanf("%d %d %d %d %d",&n,&m,&k,&s,&t)!=EOF) { s--; t--; path.clear(); for(int i=0;i<m;i++) { int u,v; scanf("%d %d",&u,&v); path.push_back(make_pair(--u,--v)); } int day=0,maxflow=0; sol.init(); sol.ClearEdge(0,n); while(maxflow<k) { int last=day*n,now=last+n; sol.ClearEdge(now,now+n); for(int i=0;i<n;i++) sol.AddEdge(last+i,now+i,INF); for(int i=0;i<n;i++) { int u=path[i].first,v=path[i].second; sol.AddEdge(last+u,now+v,1); sol.AddEdge(last+v,now+u,1); } maxflow+=sol.Maxflow(s,t+now,k-maxflow); day++; } printf("%d\n",day); vector<int>loc(k,s); for(int i=0,j=0;i<day;i++) { j+=2*n; ans.clear(); while(j<(i+1)*(2*n+4*m)) { bool f1=false,f2=false; Edge e1=sol.edges[j]; if(e1.flow==1)f1=true; j+=2; Edge e2=sol.edges[j]; if(e2.flow==1)f2=true; j+=2; if(f1&&!f2)ans.push_back(make_pair(e1.from%n,e1.to%n)); if(!f1&&f2)ans.push_back(make_pair(e2.from%n,e2.to%n)); } printf("%d",ans.size()); vector<int>mov(k,0); for(int i=0;i<ans.size();i++) { int u=ans[i].first,v=ans[i].second; for(int j=0;j<k;j++) { if(loc[j]==u&&!mov[j]) { mov[j]=1; loc[j]=v; printf(" %d %d",j+1,v+1); break; } } } printf("\n"); } } return 0; }
UVALive 2957 Bring Them There (最大流+拆点)
标签:
原文地址:http://blog.csdn.net/u012313382/article/details/46125151