一道思维细节题,没有什么难点。这种题想到就行,没想到错误找一辈子.../(ㄒoㄒ)/~~
POJ 2718:http://poj.org/problem?id=2718
题意: 给出最多10个不重复的从小到大的个位数, 将它们任意组合为两个数字,不能有前导0。
求出,所有排列中,两个数的最小差值。
网上很多人都是用new_permution还是什么的STL里的取排列办法直接爆搜。没有尝试也不想尝试。
我的心理进程是:
两个数的要是差最小,那么他们的最高位肯定是给出的数字中相邻的两个数字。一个为小,一个为大。
然后,高位较小的数字,后面放最大的数,依次放下去。
低位较大的数字,后面放最小的数,依次放下去。
那么它们的差就是最小的。
比如说: 0 1 2 3 4 5
那么最小差值肯定在这几个数字之中。
154 203
254 301
352 401
432 501
而答案也正是 254 301。
模拟一遍后WA了。想起来没考虑数字为奇数个时。
于是添加上,当个数为奇数个时,剩下的那个数给小的数字加上。然后求差值
即 01 2 3 4 5 6
就变为了 2654 301
模拟一遍后WA了。 发现这思路根本就是错的啊!
因为此时,最小的应该是 1023 654
也就是,左边为最小的四位数,右边为最大的三位数。
终于开开心心的模拟完。交了一发,WA了...
要砸电脑了 但是后来发现是细节上,n写成len了.....
总结一下: 思路就是分为,输入的数字个数为奇数还是偶数。
若为奇数,则最小差为 最小多位数-最大低位数
若为偶数,则搜索任意两位相邻位为最高最低位,把数字填进去,搜索最小解
还要分类讨论一下,如果只有两个数字,就输出他们的差即可。
这题代码就很杂乱无章了。仅仅可借鉴思路:
#include"cstdio"
#include"cstring"
#include"queue"
#include"cmath"
#include"iostream"
#include"algorithm"
using namespace std;
#define inf 999999999
#define loop(x,y,z) for(x=y;x<z;x++)
int pos[10],n;
int ans;
int book[10];
void dfs(int m)
{
if(m==n-1)return;
if(m==0&&pos[m]==0)
{
dfs(m+1);return;
}
int l=pos[m];
int r=pos[m+1];
book[m]=book[m+1]=1;
int i,j;
int t=n/2;
for(i=0,j=1;j<t;i++)
if(!book[i])
{
book[i]=1;
r=r*10+pos[i];
j++;
}
for(i=n-1,j=1;j<t;i--)
if(!book[i])
{
book[i]=1;
l=l*10+pos[i];
j++;
}
int sum=r-l;
ans=min(ans,sum);
memset(book,0,sizeof book);
dfs(m+1);
}
void odd_cal()
{
int l=0;
int r=0;
if(pos[0]==0)
l=pos[1]*10;
else l=pos[0]*10+pos[1];
int i;
loop(i,2,n/2+1)
l=l*10+pos[i];
for(int j=n-1;j>=i;j--)
r=r*10+pos[j];
ans=min(ans,l-r);
}
int main()
{
int i,T,len;
char str[100];
scanf("%d",&T);getchar();
while(T--)
{
ans=inf;
memset(book,0,sizeof book);
gets(str);
len=strlen(str);
n=0;
loop(i,0,len)
if(str[i]!=' ')
pos[n++]=str[i]-'0';
if(n==2)
ans=abs(pos[0]-pos[1]);
else if(n%2==0)
dfs(0);
else
odd_cal();
printf("%d\n",ans);
}
return 0;
}