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
*/
posted @ 2019-05-15 15:50  qrfkickit  阅读(196)  评论(0编辑  收藏  举报