POJ1015 Jury Compromise dfs的实现

做ACM练习题目已经两个年头了,最开始脑子很混乱,后来慢慢有了感觉,AC率也大幅度提高,接下来就一些经典问题做一下回顾,这些问题涵盖了算法的多个方面,相对来说有一些较为全面的总结,也是我这些年劳动成果的一些体现,今天带来的是另一道经典题目1015的dfs实现。

首先需要说明的是,这道题系统要求是用动态规划来做,并且只有动态规划能够在规定时间内跑完。这里我要说的是dfs的实现,这种实现是不能AC的,但是算法是对的,结果也是对的。之所以不能AC还要写出来,一是因为这道题目的动态规划算法已经有其他博主提供,第二是本题的动态规划算法非常复杂,一般很难想到,可以说一般参赛选手拿到题目首先想到的应该是深搜,虽然我的这套代码不能AC,但也可以作为一种算法的学习,毕竟做题不单单是为了AC,也是为了总结。


一般来说深搜有几种方法:

1.使用堆栈,stack,每循环一次将变量放入stack中,while(!s.empty()),当栈中无数据循环结束;

2.使用还原现场的方法,嵌套递归:

 ifVisited[i]=true;//设置记号
execute();//进入下一步递归
ifVisited[i]=false;//还原现场

3.直接使用循环嵌套递归:

if(current==maxSize){
......
}
for(i=current+1;i<=maxSize;i++){
    execute(i);
}


本题我们采用的是第三种方式。


dfs(int tp,int td,int already,int start,int *tc)

是我们的递归函数,其中tp指已经选择的那些候选者的正方赞成票,td指反方赞成票,already指已经选择了多少个候选者,和上面的current相似。start代表从第start个候选者往后选,因为之前的已经遍历过了,tc是临时数组,用于存储已经选了哪些候选者。


这道题目可以作为第三种深搜方式很好的学习例子。


#include<iostream>
#include<cmath>

using namespace std;

int n,m;
int d[201],p[201];
int c[21];
int pNum,dNum;

void dfs(int tp,int td,int already,int start,int *tc){
	if(already==m){
		if(abs(td-tp)<abs(pNum-dNum)){
			pNum=tp;
			dNum=td;
			for(int i=1;i<=m;i++){
				c[i]=tc[i];
			}
			return;
		}
		else if(abs(td-tp)==abs(pNum-dNum)&&(td+tp)>(pNum+dNum)){
			pNum=tp;
			dNum=td;
			for(int i=1;i<=m;i++){
				c[i]=tc[i];
			}
			return;
		}
		else{
			return;
		}
	}
	if(m-already>n-start){
		return;
	}
	for(int i=start+1;i<=n;i++){
		tc[already+1]=i;
		dfs(tp+p[i],td+d[i],already+1,i,tc);
	}
	return;
}

void calc(){
	pNum=201;
	dNum=-201;
	int tc[21];
	for(int i=1;i<=n;i++){
		tc[1]=i;
		dfs(p[i],d[i],1,i,tc);
	}
}

int main(){
	int totalCase=0;
	cin>>n>>m;
	while(n!=0){
		totalCase++;
		for(int i=1;i<=n;i++){
			cin>>p[i]>>d[i];
		}
		calc();
		cout<<"Jury #"<<totalCase<<endl;
		cout<<"Best jury has value "<<pNum<<" for prosecution and value ";
		cout<<dNum<<" for defence:"<<endl;
		for(int i=1;i<=m;i++){
			cout<<" "<<c[i];
		}
		cout<<endl;
		cin>>n>>m;
	}
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值