SPOJ ALL All Discs Considered 搜索

题目:

http://www.spoj.com/problems/ALL/en/

题意:

有两张安装盘,每张盘上都有一些安装包,某些安装包依赖于另外一些安装包,也就安装一个安装包时,要求已经安装了特定的包,读入设备每次只能读一个盘,问要安装完所有的包最少需要换盘多少次,最后一次取出盘也算一次

思路:

刚开始并不知道从哪个盘起始会使得结果最小,所以分别以每个盘起始搜索一次取最小值。具体搜索时,记录每个点的入度,依赖关系建有向边,然后模拟安装过程:首先安装所有入度为0的点,因为这些点不依赖于其他点,这个过程中会产生某些有依赖的点所依赖的点已经被安装,把这些点放入相应的序列,等到换盘的时候安装,一直轮流换盘,一直到安装完毕为止

#include <bits/stdc++.h>

using namespace std;

const int N = 100010;

struct edge
{
    int to, next;
} g[N*2];

int cnt, head[N];
int _deg[N], deg[N];
int n, m, k;
vector<int> vec1, vec2;

inline void add_edge(int v, int u)
{
    g[cnt].to = u, g[cnt].next = head[v], head[v] = cnt++;
}

int bfs1()
{
    int num = 0;
    for(size_t i = 0; i < vec1.size(); i++)
    {
        num++;
        int v = vec1[i];
        for(int i = head[v]; i != -1; i = g[i].next)
        {
            int u = g[i].to;
            if(--deg[u] == 0)
            {//所依赖的点已安装,把当前点放入相应的序列
                if(u <= n) vec1.push_back(u);
                else vec2.push_back(u);
            }
        }
    }
    vec1.clear();
    return num;
}
int bfs2()
{
    int num = 0;
    for(size_t i = 0; i < vec2.size(); i++)
    {
        num++;
        int v = vec2[i];
        for(int i = head[v]; i != -1; i = g[i].next)
        {//所依赖的点已安装,把当前点放入相应的序列
            int u = g[i].to;
            if(--deg[u] == 0)
            {
                if(u <= n) vec1.push_back(u);
                else vec2.push_back(u);
            }
        }
    }
    vec2.clear();
    return num;
}
void init()
{
    vec1.clear();
    vec2.clear();
    //初始把所有无依赖的点加入序列
    for(int i = 1; i <= n; i++)
        if(deg[i] == 0) vec1.push_back(i);
    for(int i = n+1; i <= n+m; i++)
        if(deg[i] == 0) vec2.push_back(i);
}
int work()
{
    int cnt = 0, res1 = 0, res2 = 0;
    for(int i = 1; i <= n+m; i++) deg[i] = _deg[i];
    init();
    while(true)
    {
        cnt += bfs1();
        res1++;
        if(cnt == n+m) break;
        cnt += bfs2();
        res1++;
        if(cnt == n+m) break;
    }
    cnt = 0;
    for(int i = 1; i <= n+m; i++) deg[i] = _deg[i];
    init();
    while(true)
    {
        cnt += bfs2();
        res2++;
        if(cnt == n+m) break;
        cnt += bfs1();
        res2++;
        if(cnt == n+m) break;
    }
    return min(res1, res2);
}
int main()
{
    while(scanf("%d%d%d", &n, &m, &k), n || m || k)
    {
        cnt = 0;
        memset(head, -1, sizeof head);
        memset(_deg, 0, sizeof _deg);
        for(int i = 0; i < k; i++)
        {
            int v, u;
            scanf("%d%d", &v, &u);
            add_edge(u, v);
            _deg[v]++;
        }
        printf("%d\n", work() + 1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值