1004. To Buy or Not to Buy - Hard Version (35)

感想:这道是我做过的顶级题里最恶心最恶心的题目,最后一个测试点是啥啊根本过不去好吗

1.网上大多数是用DFS+剪枝的,我是用的dp方程,但是dp方程因为可能性有2^100这么大,所以也不是特别好,两个方法55开吧,剪枝点已经在代码里标出来了

2.最后一个点过不去我实在没办法看了网上的解答,最后还是采用了他们的近似解(简单的说就是偷懒利用数据漏洞),我发现解不会超过150,所以所有的解超过150的部分项我都直接删掉了,然后就过了


#include<iostream>
#include<vector>
#include<map>
#include<deque>
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
string p[103];
string s;//需求字符串 
int use[64][101];//储存从N-1到i的符合要求的字符数量数组 
int N,m=100000,c=100000;//const int INF=100000;
int exc(char c){
	if(c<='9'&&c>='0')
	return c-'0';
	if(c<='z'&&c>='a')
	return 10+c-'a';
	else
	return 36+c-'A';
}
void get_use(){
	int a[64],i,j;
	for(i=0;i<64;i++)
	a[i]=0;
	for(i=N-1;i>=0;i--){
		for(j=0;j<p[i].size();j++){
			a[exc(p[i][j])]++;
		}
		for(j=0;j<64;j++)
		use[j][i]=a[j];
	}
}
map<vector<short>,short> ma,be;
struct ret{
	vector<short> v;
	short sum; 
};
ret add(vector<short> a,short b,int d){
	for(int i=0;i<p[d].size();i++){
		if(a[exc(p[d][i])]>0){
			a[exc(p[d][i])]--;
		}
		else
		b++;
	}
	ret ans;
	ans.sum=b;
	ans.v=a;
	return ans;
}
/*void dfs(int price,vector<int> v,vector<int> isread){
	if(ma.find(isread)!=ma.end())
	return;
	ma[isread]='1';
	vector<int> temp=v;
	int i,j,k=0;
	for(i=0;i<70;i++)
	if(v[i]!=0)
	k+=v[i];
	if(c>k)
	c=k;
	if(k==0){
		if(price<m)
			m=price; 
		return ;
	} 
	for(i=0;i<N;i++){
		k=0;
		if(isread[i]==0){
			isread[i]=1;
			for(j=0;j<p[i].size();j++){
				if(v[exc(p[i][j])])
				v[exc(p[i][j])]--;
				else
				k++;	
			}
			dfs(price+k,v,isread);
			isread[i]=0;
			v=temp;
		}
	}
	
}*/
vector<short> v;
bool iszero(int i){
	int j;
	for(j=0;j<p[i].size();j++){
		if(v[exc(p[i][j])]>0)
		return false;
	}
	return true;
}
bool com1(const string &a,const string &b){
	int i,s1=0,s2=0;
	for(i=0;i<a.size();i++)
	if(v[exc(a[i])]>0)
	s1++;
	for(i=0;i<b.size();i++)
	if(v[exc(b[i])]>0)
	s2++;
	return s1>s2;
}
bool useless(map<vector<short>,short> ::iterator &it,int j){
	int i;
	for(i=0;i<64;i++){
		if(use[i][j]<it->first[i])
		return true;
	}
	return false;
}
int main(){
	int i,j,k;
	vector<short> empty,e;
	cin>>s;
	map<vector<short>,short> ::iterator it,it2;
	for(i=0;i<64;i++){
		v.push_back(0);
		empty.push_back(0);
	}
	for(i=0;i<s.size();i++)
	v[exc(s[i])]++;
	e=v;
	ma[v]=0;
	cin>>N;
	for(int o=0;o<N;o++)
		cin>>p[o];
	sort(p,p+N,com1);
	for(int o=0;o<N;o++){
		for(j=0;j<p[o].size();j++)
		if(e[exc(p[o][j])]>0)
		e[exc(p[o][j])]--;
	}
	k=0;
	for(i=0;i<64;i++){
		if(e[i]>0)
		k+=e[i];
	}
	if(k!=0){//剪枝1 
		cout<<"No "<<k<<endl;
		return 0;
	}
	get_use();
	//dfs(0,v,isread);
	k=100000;
	for(j=0;j<N;j++){
		if(iszero(j))//剪枝2 
		continue;
		be=ma;
		for(it=be.begin();it!=be.end();it++){
			if(it->first!=empty){//剪枝3 
				if(useless(it,j)){//剪枝4 
					ma.erase(ma.find(it->first));
					continue;
				}
				//if(ma.find(empty)!=ma.end())
				if(it->second>150){//最后我屈服了,这测试点真的恶心,经测试答案不会大于150 //剪枝5 
				ma.erase(ma.find(it->first));
				continue;
				} 
				
			ret ans=add(it->first,it->second,j);
			if(ans.v==it->first)
			continue;
			if(ma.find(ans.v)==ma.end()){
				ma[ans.v]=ans.sum;
			}
			else{
				ma[ans.v]=min(ma[ans.v],ans.sum);
			}
			}
			else{
				if(it->second==0){//剪枝6 
					cout<<"Yes 0"<<endl;
					return 0;
				}
				
			}
		}	
	}
	cout<<"Yes "<<ma[empty]<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值