1. 程式人生 > >poj1011——剪枝dfs搜尋題

poj1011——剪枝dfs搜尋題

題意:

有好多根短棍

他們可以組合成n個長度相同的長棍

求長棍的最短值

粗略參考了網上的1個剪枝技巧:排序,捨棄 之前相同長卻搜失敗的棍子

然後開始自己編寫

發現速度超時, 對著數字推演半天,最終發現len=0,也就是搜新棍子,但是往下搜卻失敗,那麼這根棍子將不存在,這是不可能的,所以直接要直接跳回上級

明天開始回顧圖論,看看華為的那個參賽題到底難不難微笑

#include<stdio.h>
#include<string.h>
#include<math.h>
#define M 2000

int flag[M],stick[M];
int stick_n,want_len,ans_flag,bad_flag;
void dfs(int n,int len)
{
	int i,change_flag=1;
	if(ans_flag==1) //如果已經發現答案,則退出
		return ;
	if(len>want_len) //如果len比假設棍長 大,則退出
		return ;
	if(len==want_len)  //如果等於假設棍長,則看n
	{
		if(n==stick_n)  //相等,說明找到答案
		{
			ans_flag=1;
		}
		else
			len=0; //否則,說明已經找到一組假設棍長組合,len重置0.往下繼續找
	}

	for(i=0;i<stick_n&&ans_flag!=1&&bad_flag!=1;i++)
	{
		if(i!=0&&stick[i]==stick[i-1])  //如果之前與自己相同的棍子往下搜時都沒找到,則跳過
		{
			if(change_flag==0)
				continue;
		}
		else change_flag=1;

		if(flag[i]==1)  //如果棍子已被選擇過,則跳過
			continue;
		flag[i]=1;//選擇此棍
		dfs(n+1,len+stick[i]); //往下搜
		change_flag=0; //說明這個棍子沒找到,那麼與他相同的棍子往下搜肯定也失敗
		flag[i]=0; //取消此棍選擇
		if(len==0)  //如果這個棍子是新棍的第一個,dfs失敗,那麼後面此棍將不存在,這樣不合理
					//故跳過之後所有棍子的搜尋
		{
			break;
		}
	}
}
void sort()
{
	int i,j,temp;
	for(i=0;i<stick_n;i++)
		for(j=i;j<stick_n;j++)
		{
			if(stick[i]<stick[j])
			{
				temp=stick[i];
				stick[i]=stick[j];
				stick[j]=temp;
			}
		}
}

void main()
{
	int sum,i,max;
	while(scanf("%d",&stick_n),stick_n!=0)
	{
		sum=0;
		for(i=0;i<stick_n;i++)
		{
			scanf("%d",&stick[i]);
			sum+=stick[i];
			flag[i]=0;
		}
		sort();		//排序,從大到小
		max=stick[0];  //原棍長應該在max到sum之間
		ans_flag=0;
		for(i=max;i<=sum;i++)
		{
			if(sum%i!=0) //如果假設原棍長不被sum整除,則捨棄
				continue;
			want_len=i; //假設原棍長
			dfs(0,0);
			if(ans_flag==1) //發現答案,則輸出
			{
				printf("%d\n",i);
				break;
			}
		}
	}
}