关于Headmaster‘s Headache的题解报告

题目链接:Headmaster's Headache - UVA 10817 - Virtual Judge

我们观察到n这个值数据很小,因此可以想到用三进制压缩课程的状态,第i为表示第i+1个课程的状态,0表示没有人教授,1表示有一个人教授,2表示两人以上进行教授,故状态很容易就可以表示出来dp_i_j:前i个教授教授的课程状态为j的情况下花费的最小费用(第i个教授还没有考虑),推状态方程有个注意点,如果是由前面的阶段去推当前的状态会多一个枚举决策的时间花费,而由当前状态去推未来状态的则就不用花费枚举决策的时间花费,根据01背包的经验,不难推出状态转移方程来。

                                      dp_{i+1}u=min(dp_{i+1}u,dp_i_j+cost_i])

                                      dp_{i+1}j=min(dp_{i+1}j,dp_i_j)  

代码:

// Problem: UVA10817 校长的烦恼 Headmaster's Headache
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/UVA10817
// Memory Limit: 0 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<math.h>
#include<set>
#include<string>
#include<queue>
#include<cmath>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int number=1<<20;
template<typename T>
inline void read(T &x){
	x=0;
	int f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
	x*=f;
}
template<typename T>
inline void write(T x){
	if(x<0){putchar('-');x=~x+1;}
	if(x>=10) write(x/10);
	putchar(x%10+'0');
}
string al,mo;
vector<ll>g[201];
vector<ll>prime;
ll s,n,m,sum,step,v[201],mx,dp[3][number];
ll c[20];
ll count(string ans){//三进制的转成十进制类型
	ll s=0,dig=1;
	reverse(ans.begin(),ans.end());
	for(int i=0;i<(int)ans.size();i++){
		s+=(ans[i]-'0')*dig;
		dig*=10;
	}
	return s;
}
bool check(ll step){
	string ans;      //十进制转成三进制,并且用string存储
	while(step){
		ans+=(step%3+'0');
		step/=3;
	}
	for(int i=0;i<s;i++){  //判断是否题目初始化条件
		if(c[i]>0){
			if(i>=(int)ans.size()) return false;
			else if(c[i]>=2&&ans[i]=='2') continue;
			else if(c[i]<2&&(ans[i]-'0')>=c[i]) {continue;}
			else return false;
		}
	}
	return true;
}
ll merge(ll step,ll b){  //把某个课程的状态给更新了,并且返回这个数
	string ans;
	ll mo=step;
	while(step){
		ans+=(step%3+'0');
		step/=3;
	}
	for(int i=1;i<=10;i++) ans+='0';
	for(auto i:g[b]){
		if(ans[i]=='0') ans[i]='1';
		else if(ans[i]=='1') ans[i]='2';
	}
	ll ss=0,dig=1;
	for(int i=0;i<(int)ans.size();i++){
		ss+=dig*(ans[i]-'0');
		dig*=3;
	}
	return ss;
}
int main(){
	while(read(s),read(n),read(m),s!=0||n!=0||m!=0){
		sum=0;
		memset(c,0,sizeof(c));
		for(int i=1;i<=m;i++){
			g[i].clear();
		}
		prime.clear();
	  for(ll i=1;i<=n;i++){
		  getline(cin,al);
		  for(int k=0;(al[k]-'0')>=0&&(al[k]-'0')<=9;k++) step=k;
		  step++;
		  mo=al.substr(0,step);
		  sum+=count(mo);
		  for(int k=step+1;k<(int)al.size();k++){
			  if(al[k]==' ') continue;
			  c[al[k]-'0'-1]++;
		  }
	  }
	  for(ll i=1;i<=m;i++){
		  getline(cin,al);
		  for(int k=0;(al[k]-'0')>=0&&(al[k]-'0')<=9;k++) step=k;
		  step++;
		  mo=al.substr(0,step);
		  v[i]=count(mo);
		  for(int k=step+1;k<(int)al.size();k++){
			  if(al[k]==' ') continue;
			  g[i].push_back(al[k]-'0'-1);
		  }
	  }
	  mx=pow(3,s);
	  for(ll i=0;i<mx;i++){
	  	if(check(i)) prime.push_back(i);
	  }
	  memset(dp,0x3f3f3f3f,sizeof(dp));
	  int u=1;
	  dp[u][prime[0]]=sum;//滚动数组优化
	  for(int i=1;i<=m;i++){
	  	for(auto j:prime){
	  		ll st=merge(j,i);
	  		dp[u^1][st]=min(dp[u^1][st],dp[u][j]+v[i]);//
	  		dp[u^1][j]=min(dp[u^1][j],dp[u][j]);//
	  	}
	  	for(auto j:prime){
	  		dp[u][j]=0x3f3f3f;
	  	}
	  	u^=1;
	  }
	  cout<<dp[u][mx-1]<<endl;
	}
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
创建校长信息表`HeadMaster`的SQL语句如下: ``` CREATE TABLE HeadMaster ( HeadID CHAR(4) NOT NULL, Head_Name CHAR(10) NOT NULL, S_ID CHAR(4) NOT NULL, App_Date DATETIME, CONSTRAINT PK_HeadMaster PRIMARY KEY (HeadID), CONSTRAINT FK_HeadMaster_S_ID FOREIGN KEY (S_ID) REFERENCES School(S_ID) ); ``` 其中,`HeadID`、`Head_Name`、`S_ID`、`App_Date`分别是校长信息表`HeadMaster`的列名,对应的中文列名分别是校长编号、姓名、学校编号、任职日期。数据类型和长度分别如题所述。`App_Date`列为校长的任职日期,使用了`Datetime`类型。 主键约束使用`PK_HeadMaster`名称进行命名,外键约束使用`FK_HeadMaster_S_ID`进行命名,对应`S_ID`列的外键关系。约束必须引用`School`表的`S_ID`列。 以上SQL语句创建了一个校长信息表`HeadMaster`,其中主键为`HeadID`列,`S_ID`列为`School`表的外键。 创建学校信息表`School`的SQL语句如下: ``` CREATE TABLE School ( S_ID CHAR(4) NOT NULL, S_Name VARCHAR(20) NOT NULL, s_add CHAR(20), CONSTRAINT PK_School PRIMARY KEY (S_ID) ); ``` 其中,`S_ID`、`S_Name`、`s_add`分别是学校信息表`School`的列名,对应的中文列名分别是学校编号、学校名称、学校地址。数据类型和长度分别如题所述。 主键约束使用`PK_School`名称进行命名。 以上SQL语句创建了一个学校信息表`School`,其中主键为`S_ID`列。 创建教师类型表`TeacherType`的SQL语句如下: ``` CREATE TABLE TeacherType ( TypeID CHAR(4) NOT NULL, TypeName CHAR(20) NOT NULL, CONSTRAINT PK_TeacherType PRIMARY KEY (TypeID) ); ``` 其中,`TypeID`、`TypeName`分别是教师类型表`TeacherType`的列名,对应的中文列名分别是类型编号、类型名称。数据类型和长度分别如题所述。 主键约束使用`PK_TeacherType`名称进行命名。 以上SQL语句创建了一个教师类型表`TeacherType`,其中主键为`TypeID`列。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值