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
*/

转载于:https://www.cnblogs.com/kickit/p/10869886.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值