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