poj 1702

问题描述:

有一个天平和20个砝码,砝码的重量分别为1, 3, 9, 27,...,3^19,要求合理地把其中某些砝码放到天平的两边,测量出给定物体的重量w(1<w<(3^20-1)/2),待测物体放置在天平的左侧。

 

分析

左侧砝码总重+物体重量=右侧砝码总重

物体重量=右侧砝码总重-左侧砝码总重

所以,问题可以转化为:给出正整数w,对3^i(0<=i<=19)加上权值s (s=-1,0或者1),使得所有项的总和为w。s=-1对应于砝码放在天平左侧,s=1对应于砝码放在天平右侧,s=0对应于不使用该砝码。列举前10项的情形如下:


通过观察,这个表格和基数为3的“进位制”问题很像(如果对最基础的进位制问题的原理和方法不清楚,建议先了解一下)。我们不妨定义映射f : {0,1,2}-->{0,1,-1},即可将n%3的值相应转换为这里所要求的权值。这里还有一个问题,除第一项以外,之后每一项的“第一个周期”都是不完全的,所以对迭代过程中的n=n/3要作一个修正,考察图中的5,6,7,这三个数的后几项和2相同(红框所示),所以迭代过程应该将5,6,7转换到2,同理2,3,4-->1,8,9,10-->3等等,n=n/3最后修正为n=(n+1)/3。

 

核心代码

index = 0;

int table[3] = {0,1,-1};

while (n) {

       num[index] = table[n%3];

       n = (n+1)/3;

       index++;

}

// 1702.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"


#include<iostream>
using namespace std;

int main()
{
	int N;
	cin>>N;
	int num[20];
	int table[3]={0,1,-1};
	long long pow3[64];
	pow3[0]=1;
	for(int i=1;i<64;i++)
		pow3[i]=pow3[i-1]*3;
	while(N--)
	{
		memset(num,0,20*sizeof(num[0]));
		int nums;
		cin>>nums;
		int index=0;
		while(nums)
		{
			num[index]=table[nums%3];
			nums=(nums+1)/3;
			index++;
		}
		bool flag=false;
		int count=1;
		for(int i=0;i<index;i++)
		{
			if(num[i]==-1)
			{
				flag=true;
				if(count==1)
				cout<<pow3[i];
				else
					cout<<","<<pow3[i];
				count++;
			}
		}
		if(!flag)
			cout<<"empty"<<" ";
		else
			cout<<" ";
		count=1;
		for(int i=0;i<index;i++)
		{
			if(num[i]==1)
			{
				if(count==1)
				cout<<pow3[i];
				else
					cout<<","<<pow3[i];
				count++;
			}
		}
		cout<<endl;
		
	}
	system("pause");
	return 0;
}

原文地址:https://www.cnblogs.com/zhanglanyun/p/2090850.html