POJ_All Discs Considered

总时间限制: 
10000ms 
内存限制: 
65536kB
描述
Operating systems are large software artefacts composed of many packages, usually distributed on several media, e.g., discs. You probably remember the time when your favourite operating system was delivered on 21 floppy discs, or, a few years later, on 6 CDs. Nowadays, it will be shipped on several DVDs, each containing tens of thousands of packages. 

The installation of certain packages may require that other packages have been installed previously. Therefore, if the packages are distributed on the media in an unsuitable way, the installation of the complete system requires you to perform many media changes, provided that there is only one reading device available, e.g., one DVD-ROM drive. Since you have to start the installation somehow, there will of course be one or more packages that can be installed independently of all other packages. 

Given a distribution of packages on media and a list of dependences between packages, you have to calculate the minimal number of media changes required to install all packages. For your convenience, you may assume that the operating system comes on exactly 2 DVDs. 
输入
The input contains several test cases. Every test case starts with three integers N1, N2, D. You may assume that 1<=N1,N2<=50000 and 0<=D<=100000. The first DVD contains N1 packages, identified by the numbers 1, 2, ..., N1. The second DVD contains N2 packages, identified by the numbers N1+1, N1+2, ..., N1+N2. Then follow D dependence specifications, each consisting of two integers xi, yi. You may assume that 1<=xi,yi<=N1+N2 for 1<=i<=D. The dependence specification means that the installation of package xi requires the previous installation of package yi. You may assume that there are no circular dependences. The last test case is followed by three zeros.
输出
For each test case output on a line the minimal number of DVD changes required to install all packages. By convention, the DVD drive is empty before the installation and the initial insertion of a disc counts as one change. Likewise, the final removal of a disc counts as one change, leaving the DVD drive empty after the installation.
样例输入
3 2 1
1 2
2 2 2
1 3
4 2
2 1 1
1 3
0 0 0
样例输出
3
4
3
来源
Ulm Local 2004


神奇的题目,看题就看不懂

题目的大致意思:我们再给早期电脑装软件,用两个盘,但是只有一个接口,一次只能插入一个盘。问题时,一个dvd 盘上的软件x 是依赖于 另一个dvd盘上的软件y

所以在把所有软件安装上去的时候,要考虑安装的顺序问题(必须先装y才能装x),我们的目标是让来回换盘的次数最小。

思路: 参考别人的思路,和顺序有关的,会考虑到拓扑排序。不过这个题目是拓扑排序的一个变种。因为顺序是跨盘的,所以会出现两个子图,如第二个输入,

3 <- 1 , 2 <- 4 的情况。关键问题是如何解决这前后两个节点集合的问题。考虑用两个队列。一个队列存放n1的集合,另一个存放n2的集合。(n1 n2 代表每个光盘上的软件集合)

具体算法如下

1,拓扑排序时,先找前n1个点是的拓扑排序序列,对于每个入度为0的点,把它与之相连的点的入度减一。(可以理解为去除对该点的依赖)

2,再对另一个分量(后n2个点集合),做基本拓扑排序算法,

3,换盘的次数加1

4,重复1,2,3直到所有点的入度为0.


note:

上面的算法要做2次,因为第一次排序是从n1点开始的,所以有可能从n2点集开始换盘的次数更少。

最后取个min。

AC代码:


#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
queue<int> q[2];
const int maxn = 120000 ;
struct node{
	int x;
}nodelist[maxn];
int degree[maxn];
int degree_tmp[maxn];

int n1,n2,D; int N;
int a,b; // a->b 
vector<int> adj[maxn];

int topoSort(int n){
	int sum = 0;
	for(int i = 1; i <= N;i++){
		if(degree[i] == 0)
        {
            if(i <= n1) q[0].push(i) ; // n1 
            else q[1].push(i) ; // n2 
        }
	}
	while(!q[1].empty() || !q[0].empty()){
		while(!q[n].empty()){
		 int u = q[n].front();
		 q[n].pop();
		  for(int i = 0;i < adj[u].size(); i++ ){
		  	int index = adj[u][i];
		  	degree[index] --;
			 if(degree[index] == 0){
			 	if(index <=n1) q[0].push(index);
			 	else q[1].push(index);
			 } 
		  }	
		}
		n = n==1 ? 0: 1;
		sum++; //更换光盘操作 
	}
	return sum+1; //取盘操作,要加1。 
	
}


int main(){
	//freopen("1778.txt","r",stdin);
	while(cin >>n1 >> n2>> D){
		memset(degree,0,sizeof(degree));
		memset(degree_tmp,0,sizeof(degree));
		if(n1 ==0 && n2 == 0 && D ==0){
			break;
		}
		N = n1 + n2;
		while(D--){
		cin >> a >> b;
		degree[a] ++;
		degree_tmp[a] ++; // degree of b ++
		adj[b].push_back(a);	
		}
		int t1 = topoSort(0);
		for(int i=1;i <=N ;i++){
			degree[i] = degree_tmp[i];
		}
		int t2 = topoSort(1); 
		cout<<min(t1,t2)<<endl; //遍历2遍,因为两个盘都可能存在入度为0的点,先从第一盘,再从第二盘,注意还原degree的值 
		for(int i=1;i <=N ;i++){
			adj[i].clear(); 
		}
	}
	
	return 0;
} 











  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值