• 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
    ",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
    ",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
    */
    
  • 相关阅读:
    c#冒泡排序算法和快速排序算法
    sqlserver 索引
    varchar和Nvarchar区别
    trigger
    sql语句
    超实用压力测试工具-ab工具
    js 页面离开前触发事件
    C# websocket与html js实现文件发送与接收处理
    C# socket编程 使用fleck轻松实现对话 https://github.com/statianzo/Fleck
    C# socket编程 使用udp实现单对单的连接对话
  • 原文地址:https://www.cnblogs.com/kickit/p/10869886.html
Copyright © 2020-2023  润新知