HDU1495-非常可乐

看到网上这道题好像没有记忆化dfs的写法,我就在这里简单说一下吧。(296ms)

/*

	by:lwq132lwq

*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string.h>
#define IO ios::sync_with_stdio(false);cin.tie(0);
#define ll long long
#define dd double
#define re register
#define il inline
#define pb push_back
#define fr frist
#define sc second
#define rep(i,a,n) for(register int i=a;i<=n;i++)
#define fep(i,a,n) for(register int i=n;i>=a;i--)
using namespace std;
template <class T> void read(T &x){
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9'){f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;return ;
}
bool cmp(int x,int y){return x>y;}
dd ddabs(double x){if(x<0) return -x;else return x;}
int gcd(int a, int b){return b ? gcd(b,a%b):a;}
int max(int a,int b){if(a>b) return a;else return b;}
int min(int a,int b){if(a<b) return a;else return b;}
int qkpow(int x,int y){int ans=1;while(y){if(y&1) ans*=x;y>>=1;x*=x;}return ans;}
const double eps=1e-6;
const int maxn=1e6+10;
int n,s,m,ans=1e9;
int f[101][101][101];
void dfs(int S,int N,int M,int c)
{	
//	debug: 						  cout<<"S=="<<S<<" N=="<<N<<" M=="<<M<<" C=="<<c<<"\n";
	if((S==N&&S+N==s)||(S==M&&S+M==s)||(M==N&&M+N==s))		   {ans=min(ans,c);return ;}
	if(N+M<=m) if(!f[S][0][N+M])         f[S][0][N+M]=1,dfs(S,0,M+N,c+1),f[S][0][N+M]=0;
	if(N+M<=n) if(!f[S][N+M][0])   		 f[S][N+M][0]=1,dfs(S,M+N,0,c+1),f[S][N+M][0]=0;
	if(N+S<=s) if(!f[N+S][0][M])   		 f[N+S][0][M]=1,dfs(S+N,0,M,c+1),f[N+S][0][M]=0;
	if(M+S<=s) if(!f[M+S][N][0])   		 f[M+S][N][0]=1,dfs(S+M,N,0,c+1),f[M+S][N][0]=0;
	if(N+S<=n) if(!f[0][N+S][M])   		 f[0][N+S][M]=1,dfs(0,S+N,M,c+1),f[0][N+S][M]=0;
	if(M+S<=m) if(!f[0][N][M+S])   		 f[0][N][M+S]=1,dfs(0,N,S+M,c+1),f[0][N][M+S]=0;			
	if(S>=m-M) if(!f[S-m+M][N][m]) f[S-m+M][N][m]=1,dfs(S-m+M,N,m,c+1),f[S-m+M][N][m]=0;
	if(S>=n-N) if(!f[S-n+N][n][M]) f[S-n+N][n][M]=1,dfs(S-n+N,n,M,c+1),f[S-n+N][n][M]=0;	
	if(N>=m-M) if(!f[S][N-m+M][m]) f[S][N-m+M][m]=1,dfs(S,N-m+M,m,c+1),f[S][N-m+M][m]=0;	
	if(M>=n-N) if(!f[S][n][M-n+N]) f[S][n][M-n+N]=1,dfs(S,n,M-n+N,c+1),f[S][n][M-n+N]=0;
}
int main()
{
	while(true)
	{
		read(s);read(n);read(m);ans=1e9;
		if(n==0&&s==0&&m==0) break;
		memset(f,0,sizeof(f));
		if(s%2||s!=n+m) cout<<"NO"<<"\n";
		else 
		{
			f[s][0][0]=1; dfs(s,0,0,0);
			if(ans==1e9) cout<<"NO"<<"\n";
			else cout<<ans<<"\n";
		}
	}
	return 0;
}

我这里分了十种情况来写:

定义三个杯子:S,N,M;

1.把N中所有的可乐倒进M中

2.把M中所有的可乐倒进N中

3.把N中所有的可乐倒进S中

4.把M中所有的可乐倒进S中

5.把S中所有的可乐倒进N中

6.把S中所有的可乐倒进M中

7.把S中部分的可乐倒进M中,使得M==m

8.把S中部分的可乐倒进N中,使得N==n

9.把N中部分的可乐倒进M中,使得M==m

10.把M中部分的可乐倒进N中,使得N==n

注意:在这里我们不需要(把N或者M中的部分可乐倒回去使得S==s,因为这样就回到我们的初始状态了,所以我们不需要写这种情况)

我们对一些情况进行特判,当s是奇数的情况下是不可能成功的,因为有小数我们没法处理。其他情况下如果我们的答案等于{1e9}的话就是NO。

最快最简单的方法是数论(31ms),在这里放一个链接HDU 1495 非常可乐(数论)大家可以自己去看(有证明)。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值