码迷,mamicode.com
首页 > 编程语言 > 详细

hdu 5098 Smart Software Installer 拓扑排序or记忆化搜索

时间:2015-05-07 22:04:46      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:记忆化搜索   拓扑排序   

Smart Software Installer

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 416    Accepted Submission(s): 124


Problem Description
The software installation is becoming more and more complex. An automatic tool is often useful to manage this process. An IT company is developing a system management utility to install a set of software packages automatically with the dependencies. They found that reboot is often required to take effect after installing some software. A software package cannot be installed until all software packages it depends on are installed and take effect. 

In the beginning, they implemented a simple installation algorithm, but the system would reboot many times during the installation process. This will have a great impact on the user experience. After some study, they think that this process can be further optimized by means of installing as much packages as possible before each reboot.

Now, could you please design and implement this algorithm for them to minimize the number of restart during the entire installation process?
 

Input
The first line is an integer n (1 <= n <= 100), which is the number of test cases. The second line is blank. The input of two test cases is separated by a blank line.

Each test case contains m (1 <= n <= 1000) continuous lines and each line is no longer than 1024 characters. Each line starts with a package name and a comma (:). If an asterisk (*) exists between the package name and the comma, the reboot operation is required for this package. The remaining line is the other package names it depends on, separated by whitespace. Empty means that there is no dependency for this software. For example, “a: b” means package b is required to be installed before package a. Package names consist of letters, digits and underscores, excluding other special symbols.

Assume all packages here need to be installed and all referenced packages will be listed in an individual line to define the reboot property. It should be noted that cyclic dependencies are not allowed in this problem.
 

Output
For each test case, you should output a line starting with “Case #: " (# is the No. of the test case, starting from 1) and containing the reboot count for this test case. (Refer to the sample format)
 

Sample Input
2 glibc: gcc*: glibc uefi*: gcc*: raid_util*: uefi gpu_driver*: uefi opencl_sdk: gpu_drivergcc
 

Sample Output
Case 1: 1 Case 2: 2


链接:http://acm.hdu.edu.cn/showproblem.php?pid=5098

参考的博客:http://www.cnblogs.com/naturepengchen/articles/4069796.html


题意: 

第一行 案例数。 然后每个案例用空行隔开。

每个案例都有若干行 ,第一个单词表示一个软件,如果名字后面有*号,代表安装这个软件需要重启。 多个软件可以同时 一次重启 安装。然后冒号后面 表示安装这个软件需要先安装的软件。


做法:

有两种做法,不过都需要先建图。用get函数来把字符串变成编号。  id 表示冒号前的软件,fu表示冒号后面的软件。要把 id 存入 vector son[fu], 就像树一样存。然后把 id的入度++;


第一种做法,拓扑排序。把入度为0的 且不需要重启的 存入q1队列,然后把 入度为0 的需要重启的存入 q2 队列。然后每次先把q1 队列里的 儿子们的入度都--, 如果某个儿子入度成了0,那么就代表这个儿子的父亲都已经安装好了,就是可以安装了,如果他需要重启,就入q2, 不需要入q1。 然后q1空了之后,就表示可以安装的,且不需要重启的都已经安装好了。然后安装q2队列了,把q2 队列 全放到q1就行了,然后重启次数++,表示一次重启,然后把他们都安装完了。

这种做法感觉像模拟一样,就是不断把入度0的处理掉。


第二种做法,记忆化搜索。dp[i]表示安装第i个软件需要多少步。然后dfs所有入度为0的,搜所有儿子,搜最大路径权值和。需要重启的权值为1,不需要权值为0。



代码:

第一种做法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <stack>
#include <queue>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <sstream>
#define INF 999999999
#define eps 0.00001
#define LL __int64d
#define pi acos(-1.0) 

map<string ,int> my;

int reb[2010];
int du[2010];//入度 
int dp[2010];//每个点下去最小步数
vector<int> son[2010];
int cnt;
int get(string na)
{
	if(my.count(na)==0)
	{
		my[na]=cnt;
		return cnt++; 
	}
	else
		return my[na];
}

int deal()
{
	queue <int > q1,q2;//不需要重启  需要重启
	for(int i=0;i<cnt;i++)
	{
		if(du[i]==0)
		{
			if(reb[i]==0)
				q1.push(i);
			else
				q2.push(i);
		}
	} 
	int ans=0; 
	while(!q1.empty()||!q2.empty())
	{
		while(!q1.empty())
		{
			int num=q1.front();
			q1.pop();

			for(int i=0;i<son[num].size();i++)
			{
				du[son[num][i]]--;
				if(du[son[num][i]]==0)
				{
					if(reb[son[num][i]]==0)
						q1.push(son[num][i]);//不需要重启的  都可以安装掉
					else
						q2.push(son[num][i]);
				}
			}
		}
		if(!q2.empty())
			ans++;
		while(!q2.empty())
		{
			int num=q2.front();
			q2.pop();
			q1.push(num);
			
		}
		
	} 
	return ans; 
}

int main()
{ 
	int t;
	int cas=1;
	string str;
	scanf("%d%*c",&t);
	
	getline(cin,str);
	while(t--)
	{
		my.clear();	
		cnt=0;
		memset(reb,0,sizeof reb);
		memset(du,0,sizeof du); 
		for(int i=0;i<2000;i++)
			son[i].clear();
		while(getline(cin,str))
		{
			if(str.size()==0)
				break;
			
			stringstream sss;

			sss<<str;
			sss>>str;
			int mao=str.find(':');

			int id;
			if(str[mao-1]=='*')
				id=get(str.substr(0,mao-1));
			else
				id=get(str.substr(0,mao));

			if(str[mao-1]=='*') 
				reb[id]=1; 

			while(sss>>str)
			{
				du[id]++;
				son[get(str)].push_back(id); 
			}  
		}
		
		cout<<"Case "<<cas++<<": "<<deal()<<endl; 
	}
	return 0;
}
 


第二种做法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <stack>
#include <queue>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <sstream>
#define INF 999999999
#define eps 0.00001
#define LL __int64d
#define pi acos(-1.0) 

map<string ,int> my;

int reb[2010];
int du[2010];//入度 
int dp[2010];//每个点下去最小步数
vector<int> son[2010];
int cnt;
int get(string na)
{
	if(my.count(na)==0)
	{
		my[na]=cnt;
		return cnt++; 
	}
	else
		return my[na];
}

int dfs(int id)
{
	if(dp[id]!=-1)
		return dp[id];
	int ans=reb[id];
	for(int i=0;i<son[id].size();i++)
	{
		dfs(son[id][i]);
		ans=max(dp[son[id][i]]+reb[id],ans); 
	}
	return dp[id]=ans;
}

int main()
{ 
	int t;
	int cas=1;
	string str;
	scanf("%d%*c",&t);
	
	getline(cin,str);
	while(t--)
	{
		my.clear();	
		cnt=0;
		memset(reb,0,sizeof reb);
		memset(du,0,sizeof du);
		memset(dp,-1,sizeof dp);
		for(int i=0;i<2000;i++)
			son[i].clear();
		while(getline(cin,str))
		{
			if(str.size()==0)
				break;
			
			stringstream sss;

			sss<<str;
			sss>>str;
			int mao=str.find(':');

			int id;
			if(str[mao-1]=='*')
				id=get(str.substr(0,mao-1));
			else
				id=get(str.substr(0,mao));

			if(str[mao-1]=='*') 
				reb[id]=1; 

			while(sss>>str)
			{
				du[id]++;
				//父亲先
				son[get(str)].push_back(id);
				//cout<<str<<endl; 
			} 
			//cout<<str[mao]<<endl; 
			//cout<<"id"<<id<<endl;
		}

		int ans=0;
		for(int i=0;i<cnt;i++)
		{
			if(du[i]==0)
				ans=max(ans,dfs(i)); 
		}
		cout<<"Case "<<cas++<<": "<<ans<<endl; 
	}
	return 0;
}
 












hdu 5098 Smart Software Installer 拓扑排序or记忆化搜索

标签:记忆化搜索   拓扑排序   

原文地址:http://blog.csdn.net/u013532224/article/details/45566625

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!