poj 3411 搜索+剪枝

4 篇文章 0 订阅

记忆化搜索:s[status][cur] 记录在当前状态下,此刻位于cur点,到目的地所要的花费,由于一旦状态和位置确定,这个值是一定的
二进制状态表示:注意到n,m都比较小,由此启发
有一个剪枝:防止impossible时与目的地不连通而产生无限循环,
有m条边,对于每条边,最多存放在m个环中,故为m*m

 

 

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
using namespace std;
#define INF 10000000
struct pp
{
	int b,c,p,r;
	pp()
	{
		b=c=p=r=0;
	}
	pp(int _b,int _c,int _p,int _r)
	{
		b=_b;c=_c;p=_p;r=_r;
	}
};
int n,m;
int vis[2500][11];
int s[2500][11];
vector<pp>vec[100];
int min(int aa,int bb)
{
	return aa<bb?aa:bb;
}
int ans;
int renew(int status,int pos)
{
	return status|(1<<(pos-1));
}
bool isvis(int status ,int pos)
{
	return status&(1<<(pos-1));
}
int dfs(int cur,int status,int cost)
{
	if(s[status][cur]!=-1)
		return s[status][cur];
	if(cur==n)
		return 0;
	vis[status][cur]++;
	
	int tt,sstatus,temp;
	int ret=INF;
	if(vis[status][cur]>m*m)
		return INF;
	for(int i=0;i<vec[cur].size();++i)
	{
		tt=INF;sstatus=renew(status,vec[cur][i].b);
		if(isvis(status,vec[cur][i].c))
			tt=dfs(vec[cur][i].b,sstatus,cost+vec[cur][i].p);
		temp=dfs(vec[cur][i].b,sstatus,cost+vec[cur][i].r);
		if(tt<temp)
			s[sstatus][vec[cur][i].b]=tt;
		else 
			s[sstatus][vec[cur][i].b]=temp;
		if(tt+vec[cur][i].p<temp+vec[cur][i].r)
			ret=min(ret,tt+vec[cur][i].p);
		else ret=min(ret,temp+vec[cur][i].r);
	}
	return ret;
	
}
int main ()
{
		//freopen("aa.txt","r",stdin);
		//freopen("bb.txt","w",stdout);
		while(scanf("%d%d",&n,&m)!=EOF)
		{
		for(int i=0;i<=n;++i)
			vec[i].clear();
		int a,b,c,p,r;
		for(int i=1;i<=m;++i)
		{
			scanf("%d%d%d%d%d",&a,&b,&c,&p,&r);
			vec[a].push_back(pp(b,c,p,r));
		}
		ans=INF;
		memset(vis,0,sizeof(vis));
		memset(s,-1,sizeof(s));
		ans=dfs(1,1,0);
		
		if(ans>=INF)
			printf("impossible\n");
		else
			printf("%d\n",ans);
		}
	//system("pause");
	return 0;
}
		

 


后来研究出更简洁的代码,因为参考了网上的代码,但发现这是错的

网上有人用了个强剪枝 vis[cur]>3 ,即不允许在同一条1-n的走的路径上走过一个环3次,

但下面这组数据程序就过不了,虽然在poj上过了

6 9
1 2 1 1 1
2 1 2 1 1
1 3 2 1 100
3 1 3 1 1
1 4 3 1 100
4 1 4 1 1
1 5 4 1 100
5 1 5 1 1
1 6 5 1 100

所以应该 vis[cur]>m*m

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
using namespace std;
#define INF 10000000
struct pp
{
	int b,c,p,r;
	pp()
	{
		b=c=p=r=0;
	}
	pp(int _b,int _c,int _p,int _r)
	{
		b=_b;c=_c;p=_p;r=_r;
	}
};
int n,m,ans,vis[15];
bool flag;
vector<pp>vec[100];
int min(int aa,int bb)
{
	return aa<bb?aa:bb;
}

void dfs(int cur,int cost)
{
	if(cost>=ans||vis[cur]>m*m)
		return ;
	if(cur==n)
	{
		flag=true;
		ans=cost;
		return;
	}
	vis[cur]++;
	for(int i=0;i<vec[cur].size();++i)
	{
		if(vis[vec[cur][i].c])
			dfs(vec[cur][i].b,cost+vec[cur][i].p);
		dfs(vec[cur][i].b,cost+vec[cur][i].r);
	}
	vis[cur]--;
}
int main ()
{
		//freopen("aa.txt","r",stdin);
		//freopen("bb.txt","w",stdout);
		while(scanf("%d%d",&n,&m)!=EOF)
		{
		for(int i=0;i<=n;++i)
			vec[i].clear();
		int a,b,c,p,r;
		for(int i=1;i<=m;++i)
		{
			scanf("%d%d%d%d%d",&a,&b,&c,&p,&r);
			vec[a].push_back(pp(b,c,p,r));
		}
		ans=INF;flag=false;
		memset(vis,0,sizeof(vis));
		
		dfs(1,0);
		if(ans>=INF)
			printf("impossible\n");
		else
			printf("%d\n",ans);
		}
	system("pause");
	return 0;
}
		





 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值