poj1033

    这道题不难,通过它我进一步理解了dfs。其实我现在觉着dfs本质上就是递归?我看到网上有说用栈的数据结构解决这道题,但是递归本质上不就是栈嘛~
    这道题的大意是,整理文件碎片,把同一个文件在磁盘上连续空间存放起来,文件之间也按照顺序存放在磁盘上。大致思路就是,从第一个磁盘空间开始捋,如果是空的就找到第一个文件片段所在的磁盘空间,清空该空间,把第一个文件片段移动到第一个磁盘空间。如果是非空就找到第一个磁盘空间里的文件片段应该在的空间,看这个空间是不是空,以此类推。如果形成了环(最后又回到了深搜的根节点。比如1号空间里是2号片段,2号空间里是1号片段,再去看1号空间,没完没了......)那么就要借助一个空的磁盘空间(就像汉诺塔......)多交换一步,腾空一个,就好啦~最后再把那个被扔到空的空间里的文件放回应该放的地方~
    举个有环的简单例子,就是
    1 2 3 4
    2 3 1 0
    算法的意思就是,1里面有2,那我找找2里面是不是空,如果是空把2文件直接放进2里,再找到1文件放到1里不就行了?可是2里面有3,那我再看看3,3里面有1,我要是再看1我就成驴拉磨了......所以我得想办法把空间3清空才能打破僵局,我把1文件放到4里,这样3空间就是空的,2里的文件3就可以移到3里,1的文件2就可以移到2里。不成环就更方便啦!
    下面上代码~我现在也是个坚持写注释的好孩子啦!
#include<iostream>
#include<vector> 
using namespace std;
//1.变量名不同作用域尽量避免重复 
vector<int> space;//索引为磁盘空间 
vector<int> clus;//索引为文件片段编号 
int flag=-1;//记录当前深搜的根节点 
int freespace=0;//记录放置根节点的位置 
int n;//记录磁盘空间数组长度 
int allcount=0;//记录文件占据磁盘的总空间 
void swapspace(int a,int b,int c,int d){//交换引起的space数组操作 
	space[a]=b;
	space[c]=d;
	cout<<c<<" "<<a<<endl;
} 
void dfs(int k){
	if(space[k]==0){//直接把第k个文件移到第k个空间 
		swapspace(k,k,clus[k],0);
		clus[k]=k;
		return;
	}
	else{
		if(space[k]==flag){//形成了环,例如,磁盘空间1-5文件片段号分别为5 1 2 3 4 
			for(int i=1;i<n+1;i++){//找空的磁盘空间 
				if(space[i]==0){ 
					freespace=i;
					break;
				}
			}
			swapspace(freespace,flag,k,0);//空磁盘空间辅助交换 
			clus[flag]=freespace;
			swapspace(k,k,clus[k],0);
			clus[k]=k;
			return;
		}
		dfs(space[k]);//没有形成环,但是当前处理的磁盘空间被占用,就递归一下占用空间文件应该占用的空间 
		swapspace(k,k,clus[k],0);// 处理k号空间 
		clus[k]=k;
		return;
	}
}
int main(){
	int k;
	cin>>n>>k;
	int num=1;
	for(int i=0;i<n+1;i++){
		space.push_back(0);
		clus.push_back(0);
	}
	for(int i=0;i<k;i++){//初始化 
		int count;
		cin>>count;
		allcount+=count;
		for(int j=0;j<count;j++){
			int temp;
			cin>>temp;
			space[temp]=num;
			clus[num]=temp;
			num++;
		}
	}
	for(int i=1;i<allcount+1;i++){
		if(space[i]!=i){
			flag=i;
			dfs(i);
		}
	}
	if(flag==-1){//一直没有不满足题意的情况 
		cout<<"No optimization needed";
	}
	return 0;
}
    希望自己能多点时间练算法,希望老师少布置点作业,嗯。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值