题意:把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;
}