• Luogu P2754 【[CTSC1999]家园 / 星际转移问题】


    Description

    传送门


    Solution

    判断有无解可以使用并查集,如果最后地球和月球能处在同一个集合中,那么肯定可以到达,只是时间长短的问题。

    因为多个飞船是同时飞行的,这样的问题不好直接处理。考虑星球的个数特别少,这时可以考虑按照时间轴建立分层图,(S)向每个时间点的地球连容量为(INF)的有向边,每个星球向下个时间点的同一个星球连容量为(INF)的有向边,表示这个星球的人等待到了下个时间点;每个飞船所在星球向飞船下个时间点到达的星球连容量为承载人的数量的有向边,表示可以进行飞行转移。

    然后枚举时间,如果某个时间点最大流的比(k)大就输出时间,每次直接在残余网络上进行增广即可。


    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    
    const int N = 50050;	
    const int M = 100050;
    const int INF = 999999999;
    
    int n, m, s, t, head[N], num = 1, vis[N], d[N], mincost, maxflow, cur[N], k, a[5550][5550], fa[N], tim, b[500];
    
    struct Node
    {
    	int next, to, flow;
    } edge[M * 2];
    
    void Addedge(int u, int v, int w)
    {
    	edge[++num] = (Node){head[u], v, w};
    	head[u] = num;
    }
    
    void Add(int u, int v, int w)
    {
    //	cout << u << " " << v << endl;
    	Addedge(u, v, w);
    	Addedge(v, u, 0);
    	return;
    }
    
    template <class T>
    void Read(T &x)
    {
    	x = 0; int p = 0; char st = getchar();
    	while (st < '0' || st > '9') p = (st == '-'), st = getchar();
    	while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
    	x = p ? -x : x;
    	return;
    }
    
    template <class T>
    void Put(T x)
    {
    	if (x < 0) putchar('-'), x = -x;
    	if (x > 9) Put(x / 10);
    	putchar(x % 10 + '0');
    	return;
    }
    
    int Find(int x) { return fa[x] == x ? fa[x] : Find(fa[x]); }
    
    void Merge(int a, int b)
    {
    	int pa = Find(a), pb = Find(b);
    	if (pa == pb) return;
    	else fa[pa] = pb;	
    } 
    
    bool Bfs()
    {
        queue<int> q;
        for (int i = 0; i <= t; i++) d[i] = 0;
        d[s] = 1; q.push(s);
        while (!q.empty())
        {
            int u = q.front(); q.pop();
            for (int i = head[u]; i; i = edge[i].next)
                if (!d[edge[i].to] && edge[i].flow)
                {
                    d[edge[i].to] = d[u] + 1;
                    q.push(edge[i].to);
                    if (edge[i].to == t) return 1;
                }
        }
        return 0;
    }
    
    int Dinic(int x, int flow)
    {
        if (x == t || !flow) return flow;
        int rest = flow;
        for (int i = head[x]; i && rest; i = edge[i].next)
            if (edge[i].flow && d[edge[i].to] == d[x] + 1)
            {
                int v = edge[i].to;
                int tmp = Dinic(v, min(rest, edge[i].flow));
                rest -= tmp;
                edge[i].flow -= tmp;
                edge[i ^ 1].flow += tmp;
                if (!tmp) d[v] = 0;
            }
        return flow - rest;
    }
    
    int Maxflow()
    {
    	int maxflow = 0, tmp;
    	while (Bfs())
    	{
    		tmp = Dinic(s, INF);
    		if (tmp) maxflow += tmp;
    	}
    	return maxflow;
    }
    
    void Solve()
    {
    	while(Bfs())
    	{
    		for (int i = 0; i <= t; i++) cur[i] = head[i];
    		maxflow += Dinic(s, INF);
    	}
    	return; 
    }
    
    int Id(int a, int b)
    {
    	if (b == t) return t;
    	return (n + 1) * a + b;
    }
    
    int main()
    {
    	Read(n); Read(m); Read(k);
    	t = 50000;
    	for (int i = 1; i <= t; i++) fa[i] = i;
    	for (int i = 1; i <= m; i++)
    	{
    		Read(b[i]); Read(a[i][0]);
    		for (int j = 1; j <= a[i][0]; j++) 
    		{
    			Read(a[i][j]);
    			if (a[i][j] == 0) a[i][j] = n + 1;
    			if (a[i][j] == -1) a[i][j] = t;
    			if (j > 1) Merge(a[i][j], a[i][j - 1]);
    		}
    		Merge(a[i][1], a[i][a[i][0]]);
    	}
    	if (Find(t) != Find(n + 1)) { puts("0"); return 0; }
    	for (tim = 1; ; tim++)
    	{
    		Add(s, Id(tim - 1, n + 1), INF);
    		for (int i = 1; i <= m; i++) 
    		{
    			int pos1 = tim % a[i][0] == 0 ? a[i][0] : tim % a[i][0], pos2 = (tim + 1) % a[i][0] == 0 ? a[i][0] : (tim + 1) % a[i][0];
    		//	if (a[i][pos1] == t) continue;
    			Add(Id(tim - 1, a[i][pos1]), Id(tim, a[i][pos2]), b[i]);
    		}
    		while(Bfs())
    		{
    			maxflow += Dinic(s, INF);
    		}
    		if (maxflow >= k) { Put(tim); return 0; }
    		for (int i = 1; i <= n + 1; i++) Add(Id(tim - 1, i), Id(tim, i), INF);
    	}
    	return 0;
    }
    
  • 相关阅读:
    3、第3课CSS块级、行内元素、绝对定位、相对定位、固定位置20150922
    Easyui 正则表达式
    struts 标签
    源码详解Java的反射机制
    MyEclipse8.6安装 spket 插件
    有些路,只能一个人走
    HG8245获取超级管理员(telecomadmin)密码的方法
    easyui doc
    oracle建立自动增长字段
    Java实现二维码QRCode的编码和解码
  • 原文地址:https://www.cnblogs.com/Tian-Xing-Sakura/p/13097983.html
Copyright © 2020-2023  润新知