Gym 101606K Knightsbridge Rises(最大流+输出路径)

High-rise buildings in the wealthy retail district of Knightsbridge are usually built with exotichoisting machines known, in construction circles, as cranes.While it is common to mount these devices on the ground, it’s not always ideal—for example,a skyscraper building would need an equally tall crane. In these cases, the clever solution theindustry has developed is for a smaller crane to be mounted directly on top of the tower.However, this solution presents another challenge: how can such heavy equipment be brought tothe summit in the first place? The industry’s solution is to simply use a smaller crane to lift themain crane up. And if that smaller crane is still too massive, find another smaller still, and so on,until said device fits inside a pocket and can be carried up by some enterprising engineer.Once on top of the building, whether by being carried up, or by being lifted up by another cranecapable of holding its weight, a crane can be used to lift others up onto its tower. Once raised, itis not possible to transfer a crane anywhere else.We have several construction projects in progress at the moment, each with its own requirementson how heavy the loads eventually lifted from the ground need to be. Find an assignment ofcranes to buildings that can satisfy these requirements.

Input• 

One line containing an integer N (1 ≤ N ≤ 100), the number of types of cranes underour command.• N further lines, each containing a pair of space-separated integers Wi and Li (0 ≤Wi, Li ≤ 106), the weight and maximum lifting weight of the i-th crane in kilograms.• One line containing an integer M (1 ≤ M ≤ 100), the number of tower blocks.• One line containing the M space-separated integers Ti (1 ≤ Ti ≤ 106), Ti being theweight we need to be able to lift from the top of the i-th building by the end.

Output

If it is not possible to supply all of the buildings, output impossible.Otherwise, output M lines. The i-th line should contain a list of space-separated integersx1 . . . xk (1 ≤ x ≤ N), describing the order in which cranes should be raised onto the i-thbuilding from the input.



题意:有很多个起重机,每个起重机有他的重量,和能吊起的最大重量,有N座楼要建,找到一个起重机分配方案。

解题思路:很容易想到网络流,注意,起重机只能用一次,所以要拆点。然后计算最大流即可,再根据残余图把路径输出出来即可。



#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int MAXN = 1005;
const int INF = 0x3f3f3f3f;

int cnt = 1; //点的总个数,下标从1开始

typedef struct
{
    int flow;     //流量
    int capacity; //最大容量值
} maps;
maps G[MAXN][MAXN];

int layer[MAXN];              //保存标号所属层
bool countLayer(int s, int e) //宽搜
{
    int v, i;
    queue<int> q;
    memset(layer, 0, sizeof(layer));

    q.push(s);
    layer[s] = 1;
    while (!q.empty())
    {
        v = q.front();
        q.pop();
        for (i = 1; i <= cnt; i++)
            if (!layer[i] && G[v][i].capacity > G[v][i].flow)
            {
                q.push(i);
                layer[i] = layer[v] + 1;
            }
        if (v == e)
            return 1;
    }
    return 0;
}
int dfs(int cur, int cp, int e)
{
    if (cur == e)
        return cp;

    int tmp = cp, t;
    for (int i = 1; i <= cnt; i++)
        if (layer[i] == layer[cur] + 1 && tmp && G[cur][i].capacity > G[cur][i].flow)
        {
            t = dfs(i, min(G[cur][i].capacity - G[cur][i].flow, tmp), e);
            G[cur][i].flow += t;
            G[i][cur].flow -= t;
            tmp -= t;
        }
    return cp - tmp;
}
int Max_Flow_Dinic(int s, int e)
{
    int maxflow = 0;
    while (countLayer(s, e))
        maxflow += dfs(s, INF, e);
    return maxflow;
}

struct Ji
{
    int w;
    int l;
    int id;
} qzj[1005];
map<int,int> mp;

struct fj
{
    int w;
    int id;
} zd[1005];

int main()
{

    int N;
    scanf("%d", &N);
    for (int i = 0; i < N; i++)
        scanf("%d%d", &qzj[i].w, &qzj[i].l);
    int M;
    scanf("%d", &M);
    for (int i = 0; i < M; i++)
        scanf("%d", &zd[i].w);

    int S = cnt++;
    for (int i = 0; i < N; i++){
        qzj[i].id = cnt++;
        qzj[N+i].id=cnt++;
        G[qzj[i].id][qzj[N+i].id].capacity=1;
        mp[qzj[N+i].id]=i+1;//根据图编号,快速求回实际编号
        mp[qzj[i].id]=i+1;
    }
        

    for (int i = 0; i < M; i++)
        zd[i].id = cnt++;

    int T = cnt;

    for (int i = 0; i < N; i++)
        if (qzj[i].w == 0)
            G[S][qzj[i].id].capacity = 1;

    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            if (i != j)
            {
                if (qzj[i].l >= qzj[j].w)
                    G[qzj[N+i].id][qzj[j].id].capacity = 1;
            }

    for (int i = 0; i < N; i++)
        for (int j = 0; j < M; j++)
            if (qzj[i].l >= zd[j].w)
                G[qzj[N+i].id][zd[j].id].capacity = 1;

    for (int j = 0; j < M; j++)
        G[zd[j].id][T].capacity = 1;

    int flow = Max_Flow_Dinic(S, T);
   // cout<<flow<<endl;
    if (flow != M)
        printf("impossible\n");
    else
    {

        for (int i = 0; i < M; i++)
        {
            int cur = zd[i].id;
            vector<int> ans;
            while (cur != 1)
            {
                for (int j = 1; j <= cnt; j++)
                {
                    if (G[j][cur].flow == 1)
                    {
                        //G[j][cur].flow=0;

                        ans.push_back(mp[j]);
                        //cout<<j-1<<" ";
                        cur = j;
                        break;
                    }
                }
            }

            ans.pop_back();
            while (!ans.empty())
            {
                cout << ans.back() << " ";
                ans.pop_back();//因为拆了点,路径会重复,所以pop两次
                ans.pop_back();
            }
            cout << endl;
        }
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值