【dp&贪心】UVA1228 整数传输

贪心1:首先可以规定,k(待接收数)中的所有0和1均按原顺序接收,即每个数不会比k中它前面的同类数早被接收,因为每一个这样的情况,都可以调整成按原顺序接收,所以这种情况得到的数删去对答案没有影响

例如上图,调整两个0的接收顺序,会发现两个数的最大时间延迟会变小,更容易符合条件

贪心2:每当需要接收一个0或1时,一定接收k中还未被接收的最靠左的,因为这个数早晚都要接收,留到后面接收容易超出时间限制。

所以dp就是dp[i][j]表示从k中从左到右接收i个0和j个1,能形成几种数。每次有接收0和1两种决策。但这样一定会产生许多不合法决策。判断方法就是,如果当前要接收一个0,最左边未被接收的1加上d小于这个0的位置,那么这个1以后就不可能接收到了,这样这个决策就不合法。如果等于也可以,可以在接收0的同时接收到这个1,把1排到同时接收的0的后面。

还有一个细节就是要用ull,ll会爆

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL unsigned long long
using namespace std;
int n,d,m1,m0,A[200],T[200][200]; 
LL k,dp[200][200];
LL get_max(){
	int i,j;
	LL k=0;
	memset(T,0,sizeof(T));
	for (i=1;i<=n;i++)
		if (A[i]) T[i][1]++;
		else T[i+d][0]++;
	for (i=1;i<=n+d;i++){
		for (j=1;j<=T[i][1];j++) k<<=1,k++;
		for (j=1;j<=T[i][0];j++) k<<=1;
	}
	return k;
}
LL get_min(){
	int i,j;
	LL k=0;
	memset(T,0,sizeof(T));
	for (i=1;i<=n;i++)
		if (!A[i]) T[i][0]++;
		else T[i+d][1]++;
	for (i=1;i<=n+d;i++){
		for (j=1;j<=T[i][0];j++) k<<=1;
		for (j=1;j<=T[i][1];j++) k<<=1,k++;
	}
	return k;
}
LL DP(){
	memset(dp,0,sizeof(dp));
	memset(T,0,sizeof(T));
	m1=0; m0=0;
	int i,j;
	for (i=1;i<=n;i++) 
		if (A[i]) T[1][++m1]=i;
		else T[0][++m0]=i;
	dp[0][0]=1;
	for (i=0;i<=m0;i++)
		for (j=0;j<=m1;j++){
			if (i<m0&&(j==m1||T[1][j+1]+d>=T[0][i+1])) dp[i+1][j]+=dp[i][j];
			if (j<m1&&(i==m0||T[0][i+1]+d>=T[1][j+1])) dp[i][j+1]+=dp[i][j];
		}
	return dp[m0][m1];
}
int main(){
	int cnt=0,m;
	while (1){
		scanf("%d",&n);
		if (!n) break;
		cin>>d>>k; m=n;
		memset(A,0,sizeof(A));
		while (k) A[m--]=k&1,k>>=1;
		
		printf("Case %d: ",++cnt);	
		cout<<DP()<<' '<<get_min()<<' '<<get_max()<<endl;
	}
}

猜你喜欢

转载自blog.csdn.net/lerbon23james/article/details/80197462
今日推荐