SGU 304. Mars Stomatology

304. Mars Stomatology
Time limit per test: 1 second(s)
Memory limit: 65536 kilobytes
input: standard
output: standard



Martian girl Kate has a toothache. The martian anatomy is very specific. They all have N teeth, each situated on one of K gums. Kate should pay dentist Ai mars euros for the treatment of i-th tooth. Moreover, Kate should pay Bj euros for the anesthesia of the gum j if this gum has at least one tooth cured. What is the maximal number of teeth Kate can cure if parents gave her P mars euros?

Input
The first line of the input contains three integer numbers NK and P (1≤ N≤ 600; 1≤ K≤ N; 1≤ P≤ 106). The second line contains the sequence of K integer numbers B1B2,..., BK, where Bj is the cost of anesthesia of the j-th gum (1≤ Bj≤ 600 for all j = 1, 2,..., K). Each of the following N lines contains the description of tooth. Each description is the pair of integer numbers Ai and Ci, where Ai is the cost of curing of the i-th tooth, Ci is the number of the gum the tooth occupies (1≤ Ai≤ 600; 1≤ Ci≤ K for all i = 1, 2,..., N). 

Output
Write to the first line of the output the maximal number of cured teeth S. Write to the second line S numbers of the cured teeth from the given set. If there are several solutions output any of them.

Example(s)

sample input

sample output

4 2 101 21 25 23 13 2

34 3 1

 

分析:dp[i][j]表示前i个tooth,修理j个的最小花费

 

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=601;
const int INF=0x7fffffff;
struct tooth
{
	int c,b,id;
	bool operator<(tooth t)const{
	if(b!=t.b)return b<t.b;
	else return c>t.c;
	}
}t[N];
int g[N],pre[N],cost[N],dp[N][N],s[N][N];
int n,k,p;
void print(int x,int y)
{
	int i;
	if(x==0)return;
	for(i=s[x][y]+1;i<=x;i++) printf("%d ",t[i].id);
	print(pre[x],y-(x-s[x][y]));
}
int main()
{
	int i,j,k;
	while(~scanf("%d%d%d",&n,&k,&p))
	{
		for(i=1;i<=k;i++)scanf("%d",&g[i]);
		for(i=1;i<=n;i++){scanf("%d%d",&t[i].c,&t[i].b);t[i].id=i;}
		sort(t+1,t+n+1);
		for(i=1;i<=n;i++)
		{
			cost[i]=cost[i-1]+t[i].c;
			if(t[i].b!=t[i-1].b) j=i-1;
			pre[i]=j;
		}
		for(i=1;i<=n;i++)for(j=0;j<=i;j++)
		{
			dp[i][j]=INF;
			for(k=pre[i];k<=i;k++)
			{
				int t1=i-k,t2=j-t1;
				if(j>=t1&&t2<=pre[i])
				{
					if(dp[pre[i]][t2]+cost[i]-cost[k]+g[t[i].b]*(i!=k)<dp[i][j])
					{
						dp[i][j]=dp[pre[i]][t2]+cost[i]-cost[k]+g[t[i].b]*(i!=k);
						s[i][j]=k;
					}
				}
			}
		}
		for(i=n;i>0;i--)
		{
			if(dp[n][i]<=p)
			{
				printf("%d\n",i);
				print(n,i);
				break;
			}
		}
		if(i==0) puts("0");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值