CF 966 Div3 F. Color Rows and Columns

原题链接:Problem - F - Codeforces

题意:多测,每组测试数据给出n和k,n代表有n个长方形,k代表需要的到k分,每个长方形都有宽和高,每次可以填涂一个格子,如果填满一列或者一行就可以获得一分,问达到k分最少需要填涂多少格子。

赛时思路:背包dp+随机化,按照背包dp的思路来想,就是选择了某个长方形,如果填满这个长方形分数也不能到达k,那么就直接填满,如果大于等于k那么就用最小代价来填满这个长方形。可以发现这个思路并不可以通过这题,最后一个样例就过不去,发现顺序会影响dp的结果,因为这题的数据量小,并且最小的填涂格子可能不止一种方法,那么就可以想到使用随机化。

补题思路:dp,先求出dp[i][j],i代表第i个长方形,j代表这个长方形得到j分,dp[i][j]代表最小的涂色数,然后就可以理解成对于第i个长方形选择j分就要填涂dp[i][j]个格子,然后就是对于每个长方形都选择一个dp[i][j]来进行dp就可以了。

赛时代码:

//冷静,冷静,冷静
//调不出来就重构
#pragma GCC optimize(2)
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pii;
const int N=1e6+10,mod=1000000007;
struct node
{
	ll x,y;
}p[N];
ll f[1010][110];
ll dfs1(ll xz1,ll xz2,ll k)
{
	if(k<=0)return 0;
	if(xz1>xz2)
	{
		swap(xz1,xz2);
	}
	if(xz1==xz2&&xz1==1)
	{
		return 1;
	}
	ll d=0,ans=0;
	for(int i=1;i<=xz2;i++)
	{
		if(xz2-i+1<xz1)
		{
			ans+=dfs1(xz1,xz2-i+1,k);
			return ans;
		}
		if(k==0)break;
		ans+=xz1;
		k--;
	}
	return ans;
}
ll n;
ll dfs(ll x,ll k)
{
	if(k==0)return 0;
	if(x>n)
	{
		if(k)return 1e9;
		return 0;
	}
	if(f[x][k]!=-1)return f[x][k];
	ll sum=1e9;
	sum=min(sum,dfs(x+1,k));
	if(k>=p[x].x+p[x].y)
	{
		sum=min(sum,dfs(x+1,k-p[x].x-p[x].y)+p[x].x*p[x].y);
	}
	else
	{
		sum=min(sum,dfs1(p[x].x,p[x].y,k));
	}
	f[x][k]=sum;
	return f[x][k];
}
void Jiuyuan()
{
	ll k;cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>p[i].x>>p[i].y;
	}
	ll v=100;
	ll vb=1e18;
	while(v--)
	{
		memset(f,-1,sizeof(f));
		random_shuffle(p+1,p+1+n);
		ll v1=dfs(1,k);
		vb=min(v1,vb);
	}
	if(vb==1e9)
	{
		cout<<-1<<endl;
	}
	else cout<<vb<<endl;
}
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	ll T=1;
	cin>>T;
	srand(time(0));
	while(T--)
	{
		Jiuyuan();
	}
    return 0;
}

补题代码:

//冷静,冷静,冷静
//调不出来就重构
//#pragma GCC optimize(2)
//#pragma GCC optimize("O3")
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pii;
const int N=1e6+10,mod=1000000007;
struct node
{
	ll x,y;
}p[N];
ll c[1010][310],f[1010][310],n;
ll dfs(ll x,ll zhi)
{
	if(x>n&&zhi)return 1e9;
	if(zhi<0)return 1e9;
	if(zhi==0)return 0;
	if(f[x][zhi]!=-1)return f[x][zhi];
	ll min1=1e9;
	for(int i=0;;i++)
	{
		if(c[x][i]==1e9)break;
		min1=min(min1,dfs(x+1,zhi-i)+c[x][i]);
	}
	f[x][zhi]=min1;
	return min1;
}
void Jiuyuan()
{
	ll k;cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>p[i].x>>p[i].y;
		for(int j=0;j<=300;j++)
		{
			c[i][j]=1e9;
		}
	}
	memset(f,-1,sizeof(f));
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=p[i].x;j++)
		{
			for(int jk=0;jk<=p[i].y;jk++)
			{
				ll v=j+jk;
				c[i][v]=min(c[i][v],jk*p[i].x+j*p[i].y-j*jk);
			}
		}
	}
	ll v=dfs(1,k);
	if(v==1e9)
	{
		cout<<-1<<endl;
	}
	else cout<<v<<endl;
}
int main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	ll T=1;
	cin>>T;
	while(T--)
	{
		Jiuyuan();
	}
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值