uvalive 2957 Bring Them There
题意:
运送k个超级计算机,边是双向的,但是对于某一条边,一天只能运送一台机器,且不能出现同时双向运送,问最少需要多少天,并且输出每天的路径。
思路:
首先枚举天数用二分,极限情况最多100天,假设为lim;
然后把每个点都拆成\(lim\)个,表示在某天的这个点,那么对于输入的每条边\(u -> v\),在第\(i\)天就可以表示为\(u + (i-1) * n -> v + i * n\),以及\(v + (i-1) * n -> u + i * n\),按照题意,这些边的容量都是1;然后连边\(u + (i-1)*n -> u + i * n\),容量为inf,表示可以有任意多的机器停在这个点;
然后从源点到\(s\)连边,容量为k,汇点为\(t + lim * n\),然后跑最大流,判断是否满流即可;
题目中还有一个条件是不能出现双向运送,考虑对于边\(u -> v\),那么当某天这条边的双向都出现流量时,其实就两个点自己流到自己,机器在这天没有任何移动,这个想法是无比精妙的,所以这个条件就满足了;
最后是找路径,通过每天的点找指向前一天的点,记录流量,特别注意处理自己流到自己的情况,然后从\(s\)开始dfs,对于每一天的路径,判断这天的地点和前一天的地点是否相同,不同时再加入答案即可。
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 5;
struct edge
{
int u,v,cap;
edge(int u,int v,int cap):u(u),v(v),cap(cap){}
edge(){}
};
vector<int> G[N];
vector<pii> g[N];
vector<edge> es;
vector<pii> vp;
vector<pii> pos[105];
int dis[N],cur[N];
int S,T;
int vis[105][105];
int dep[N];
void adde(int u,int v,int cap)
{
es.push_back(edge(u,v,cap));
es.push_back(edge(v,u,0));
int sz = es.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
}
bool bfs()
{
memset(dis,inf,sizeof dis);
dis[S] = 0;
queue<int> q;
q.push(S);
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = 0;i < G[u].size();i++)
{
edge &e = es[G[u][i]];
int v = e.v;
if (dis[v] >= inf && e.cap > 0)
{
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
return dis[T] < inf;
}
int dfs(int u,int flow)
{
if (u == T) return flow;
for (int i = cur[u];i < G[u].size();i++)
{
cur[u] = i;
edge &e = es[G[u][i]];
int v = e.v;
if (dis[v] == dis[u] + 1 && e.cap > 0)
{
int tmp = dfs(v,min(flow,e.cap));
if (tmp)
{
e.cap -= tmp;
es[G[u][i]^1].cap += tmp;
return tmp;
}
}
}
return 0;
}
int dinic()
{
int ans = 0;
while (bfs())
{
memset(cur,0,sizeof(cur));
int tmp;
while (tmp = dfs(S,inf)) ans += tmp;
}
return ans;
}
int n,m,K,s,t;
bool meet(int lim)
{
es.clear();
for (int i = 0;i < N;i++) G[i].clear();
S = 0;
adde(S,s,K);
for (int i = 1;i <= lim;i++)
{
for (int j = 0;j < vp.size();j++)
{
int u = vp[j].first + (i-1) * n;
int v = vp[j].second + i * n;
adde(u,v,1);
u = vp[j].second + (i-1) * n;
v = vp[j].first + i * n;
adde(u,v,1);
}
for (int j = 1;j <= n;j++)
{
int u = j + (i-1) * n;
int v = j + i * n;
adde(u,v,inf);
}
}
T = t + lim * n;
int ans = dinic();
return ans >= K;
}
vector<int> anc;
void findpath(int u)
{
int tu = u % n ? u % n : n;
anc.push_back(tu);
for (int i = 0;i < g[u].size();i++)
{
int v = g[u][i].first;
int& cap = g[u][i].second;
if (cap > 0)
{
cap--;
findpath(v);
return;
}
}
}
int main()
{
while (~scanf("%d%d%d%d%d",&n,&m,&K,&s,&t))
{
vp.clear();
for (int i = 0;i < N;i++)
{
G[i].clear();
g[i].clear();
}
for (int i = 0;i < m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
vp.push_back(pii(x,y));
}
S = 0;
int l = 1,r = 200;
while (r - l > 1)
{
int mid = (l + r) >> 1;
if (meet(mid)) r = mid;
else l = mid;
}
while (r > 1 && meet(r-1)) r--;
meet(r);
for (int i = 0;i <= r;i++)
{
for (int j = 1;j <= n;j++)
{
dep[j+i*n] = i;
}
}
printf("%d\n",r);
for (int i = 1;i <= r;i++)
{
pos[i].clear();
memset(vis,0,sizeof(vis));
for (int j = 1;j <= n;j++)
{
int u = j + i * n;
for (int k = 0;k < G[u].size();k++)
{
edge e = es[G[u][k]];
int v = e.v;
if (v == S) continue;
if (e.cap > 0 && dep[v] == dep[u] - 1)
{
int tu,tv;
if (v % n == 0) tv = n;
else tv = v % n;
if (u % n == 0) tu = n;
else tu = u % n;
vis[tv][tu] = e.cap;
//printf("%d %d %d\n",tv,tu,e.cap);
}
}
}
for (int j = 1;j <= n;j++)
{
if (vis[j][j])
{
int u = j + (i-1)*n;
int v = j + i * n;
g[u].push_back(pii(v,vis[j][j]));
}
}
for (int j = 0;j < vp.size();j++)
{
int u = vp[j].first,v = vp[j].second;
if (vis[u][v] && vis[v][u])
{
int tu = (i-1) * n + u;
int tv = i * n + u;
g[tu].push_back(pii(tv,1));
tu = i * n + v;
tv = (i-1) * n + v;
g[tv].push_back(pii(tu,1));
continue;
}
if (!vis[u][v] && !vis[v][u]) continue;
if (vis[u][v])
{
int tu = u + (i-1) * n;
int tv = v + i * n;
g[tu].push_back(pii(tv,1));
}
if (vis[v][u])
{
int tu = u + i * n;
int tv = v + (i - 1) * n;
g[tv].push_back(pii(tu,1));
}
}
}
int cnt = 0;
while (1)
{
anc.clear();
findpath(s);
if (anc.size() == 1) break;
++cnt;
for (int i = 1;i < anc.size();i++)
{
if (anc[i] == anc[i-1]) continue;
pos[i].push_back(pii(cnt,anc[i]));
}
}
for (int i = 1;i <= r;i++)
{
printf("%d",(int)pos[i].size());
for (int j = 0;j < pos[i].size();j++)
{
pii tmp = pos[i][j];
printf(" %d %d",tmp.first,tmp.second);
}
puts("");
}
}
return 0;
}
/*
6 7 4 1 6
1 2
2 3
3 5
5 6
1 4
4 6
4 3
*/
康复训练中~欢迎交流!