UVa10817 Headmaster's Headache

        还是集合状态压缩dp,有了前面的经验,已经相对好写了。dp(i,j,k)表示考虑了前i个人,有1个人教的科目集合为j,有2个或更多人教的科目集合为k的最少花费。然后就是各种位运算了。。dp数组初始化为了-1,所以代码看上去比较挫。。这题不知道能不能用最小费用最大流写。。


#include <iostream>    
#include <stdio.h>    
#include <cmath>    
#include <algorithm>    
#include <iomanip>    
#include <cstdlib>    
#include <string>    
#include <memory.h>    
#include <vector>    
#include <queue>    
#include <stack>    
#include <map>  
#include <set>  
#include <ctype.h>    
#define INF 10000000
#define ll long long
#define min3(a,b,c) min(a,min(b,c))
#define max3(a,b,c) max(a,max(b,c))
#define MAXN 100010

using namespace std;  


int s;//科目  8
int m;//老师  20 
int n;//求职者  100 
int dp[110][260][260];
int cnt[10];
vector<int> appl[110];
int c[110];

int main(){
	while(cin>>s>>m>>n){
		if( !(s||m||n))break;
		memset(dp,-1,sizeof(dp));
		memset(cnt,0,sizeof(cnt));
		memset(appl,0,sizeof(appl));
		
		char list[64];
		int ts=0;
		for(int i=1;i<=m;i++){
			int a,b;
			char ch;
			cin>>a;ts+=a;
			while(scanf("%d%c",&b,&ch)){
				cnt[b]++;
				if(ch=='\n')break;
			}
		}
		
		//
		int _1=0,_2=0;
		for(int i=1;i<=s;i++){
			if(cnt[i]==1)_1+=1<<(i-1);
			if(cnt[i]>1)_2+=1<<(i-1);
		}
		dp[0][_1][_2]=0;
		//
		
		for(int i=1;i<=n;i++){
			int a,b;
			char ch;
			cin>>a;
			c[i]=a;
			while(scanf("%d%c",&b,&ch)){
				appl[i].push_back(b);
				if(ch=='\n')break;
			}
		}
		
		for(int i=1;i<=n;i++){
			
			for(int j=0;j<(1<<s);j++){
				for(int k=0;k<(1<<s);k++){
					if(dp[i-1][j][k]==-1)continue;
					if(dp[i][j][k]!=-1)dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k]);
					else dp[i][j][k]=dp[i-1][j][k];
					int _1=j,_2=k;
					for(int l=0;l<appl[i].size();l++){
						//顺序不能错 
						int t=1<<(appl[i][l]-1);
						_2=_2|(_1&t);
						_1=_1|t;
					}
					_1=_1&(~_2);
					if(dp[i][_1][_2]!=-1) dp[i][_1][_2]=min(dp[i][_1][_2],dp[i-1][j][k]+c[i]);
					else dp[i][_1][_2]=dp[i-1][j][k]+c[i];
					if(dp[i-1][_1][_2]!=-1)dp[i][_1][_2]=min(dp[i][_1][_2],dp[i-1][_1][_2]);
				}
			}
		}
		cout<<ts+dp[n][0][(1<<s)-1]<<endl;
	}
	return 0;
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值