TC SRM629 500pt CandyCollection DP

11 篇文章 0 订阅
4 篇文章 0 订阅

       有一类糖果,每个糖果有两个属性分别是形状和味道,糖果的形状可以在购买时看到,而味道在购买时是不知道的,约定每种形状的糖果,恰好只有两种不同的味道,并且对于每一种味道,恰好只有两种形状的糖果会有这种味道,现对于每一种形状的糖果,给出四个数t1,n1,t2,n2,表示这种形状的糖果,有n1个的味道是t1,n2个的味道是t2,求至少买多少个糖果,可以保证包所有0--N-1种味道。

       首先要确定几点,对于一种形状的糖果有t1,n1,t2,n2,那么我买n1+1个,可以保证买到有味道t2的糖果,买n2+1个,可以保证买到味道t1的糖果,同理,买max(n1,n2)+1个糖果,可以保证买到t1,t2这两种味道的糖果。有了这个前提,我们把味道看做节点,每个形状看做连接t1,t2的边,权值是一个二元组<n1,n2>,由于点数等于边数并且每个节点的度数相同,所以这个图一定是有一个或者几个不向交的环组成的,那么对于每个环,我们就是要用最小的代价,来覆盖所有的点,覆盖的时候,对于一条权值为<x,y>,由s指向t的边,覆盖s的代价是y+1,覆盖t的代价是x+1,同时覆盖s,t的代价是max(x,y)+1。这里可以dp求出最小覆盖的代价,dp[i][j]记录对于第i个点,向前覆盖时j=0,向后覆盖时j=1,对于0--1覆盖和n-1 --- 1覆盖的情况,赋给各自的边界条件,各自做一遍dp,最后去最小值就是覆盖这个环的最小代价。

/*=============================================================================
#  Author:Erich
#  FileName:
=============================================================================*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#define lson id<<1,l,m
#define rson id<<1|1,m+1,r

using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=1ll<<60;
const double PI=acos(-1.0);
int n,m;
struct node
{
	int x,y;
	node(){
	}
	node(int a,int b)
	{x=a; y=b;
	}
};
const int maxn=1050;
vector<int>g[maxn];
vector<node>w[maxn];
class CandyCollection
{
	public:
		int solve(vector<int> t1,vector<int> n1,vector<int> t2,vector<int> n2)
		{
			n=t1.size();
			for (int i=0; i<n; i++)
			{
				int x=t1[i],y=t2[i];
				int wx=n1[i],wy=n2[i];
				g[x].push_back(y);
				w[x].push_back(node(wx,wy));
				g[y].push_back(x);
				w[y].push_back(node(wy,wx));
			}
			int ans=0;
			for (int i=0; i<n; i++)
			if (g[i].size()==2)
			{
				int cur=i,last=-1;
				int tmp=0;
				vector<node> path(0);
				while(true)
				{
					if (g[cur][0]!=last)
					{
						path.push_back(w[cur][0]);
						last=cur;
						cur=g[cur][0];
					}
					else
					{
						path.push_back(w[cur][1]);
						last=cur;
						cur=g[cur][1];
					}
					g[last].clear();
					if (cur==i) break;
				}
				int dp[1050][2];
				memset(dp,0x3f,sizeof dp);
				int l=path.size();
				dp[0][1]=path[0].y+1;
				dp[1][1]=max(path[0].x,path[0].y)+1;
				for (int j=0; j<l; j++)
				{
				    dp[j+1][0]=min(dp[j+1][0],dp[j][1]);
				    dp[j+1][0]=min(dp[j+1][0],dp[j][0]+path[j].y+1);
				    dp[j+1][1]=min(dp[j+1][1],dp[j][0]+max(path[j].x,path[j].y)+1);
				    dp[j+1][1]=min(dp[j+1][1],dp[j][1]+path[j].x+1);
				}
				tmp=min(dp[l][0],dp[l][1]);
				memset(dp,0x3f,sizeof dp);
				dp[1][1]=path[0].x+1;
				dp[1][0]=0;
				for (int j=1; j<l; j++)
				{
				    dp[j+1][0]=min(dp[j+1][0],dp[j][1]);
				    dp[j+1][0]=min(dp[j+1][0],dp[j][0]+path[j].y+1);
				    dp[j+1][1]=min(dp[j+1][1],dp[j][0]+max(path[j].x,path[j].y)+1);
				    dp[j+1][1]=min(dp[j+1][1],dp[j][1]+path[j].x+1);
				}
				tmp=min(tmp,dp[l][1]);
				ans+=tmp;
			}

			return ans;
		}
}work;


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值