题目:
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;
}