这是11年集训时放的题目,当时深为不解,题目来源是coci。
【大意】
设有n个城镇city[0],city[1],……,city[n-1],city[i]与city[i+1]相邻( i 属于[0,n-2] ),其距离记为dist[i],若给出每两个城市之间的距离,则可以算出任意两个城市间的距离,共有n*(n-1)/2个。
现在给出这n*(n-1)/2个距离,求每两个城市之间的距离,答案可能不存在或者有很多个。
若有多个,则按照dist[i]的字典序输出。n<=20
【分析】
由于n很小,可以考虑搜索算法。
如果枚举相邻2个城市间的距离,则其复杂度为n^(n*(n-1)/2),最大为20^190,完全无法容忍。
其实这道题和论文里的一篇及其相似,关于搜索对象的问题,不同的搜索对象,不同的搜索顺序都极大的影响搜索效率。
这里可以搜索相邻2个城市间的距离,或者第1个城市到第i个城市之间的距离。
先上算法吧:
记sum[i]=dist[0] + ... + dist[i]。
分析知:最大值必为第一个城市到第n个城市间的距离,记为maxLength。
那么第二大的值呢??
显然它为dist[0]+...+dist[n-2]或者dist[1]+...+dist[n-1],否则反证法,第二大的值必然不是dist[0]+...+dist[n-1],故必是dist[0]+...+dist[n-2]或者dist[1]+...+dist[n-1]的一部分(又假设知不是全部),记为dist[i]+..+dist[j],其值显然小于前面两个,但是由于它是第二大的,那么前两个值必然不存在于那任意两个城市间的距离,矛盾,故。。
那么第三大的呢??
类似。。
假设当前最大的没用到的值为k,其中前i个和后j个距离和都算出来了,即已经搜到了sum[0]到sum[i-1]和sum[n+1-j]到sum[n],那么k必然是sum[n-j]或者maxLength-k是sum[i]。
证法同上。
于是其复杂度为O(2^n),搜索深度为n,每个值k有2次向下扩展的机会,故为O(2^n)。
这里注意每次放置的时候将改点到其他已知点的距离都减掉。
附个链接:soj4059
附个代码:
#include <string.h>
#include <stdio.h>
#include <set>
#include <ctype.h>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;
const int maxn = 512 ;
int ans[32] , dist[maxn] , cnt[maxn] , end , num[maxn] , myCount[maxn] , top , n , iCount ;
vector<int> ve ;
struct node {
int array[20] ;
}hb[maxn*maxn] ;
struct cmp {
int operator()(const int a,const int b) const
{
return memcmp(hb[a].array,hb[b].array,sizeof(int)*(n-1)) < 0 ;
}
};
inline bool get(int &t)
{
bool flag = 0 ;
char c;
while(!isdigit(c = getchar())&&c!='-') if( c == -1 ) break ;
if( c == -1 ) return 0 ;
if(c=='-') flag = 1 , t = 0 ;
else t = c ^ 48;
while(isdigit(c = getchar())) t = (t << 1) + (t << 3) + (c ^ 48) ;
if(flag) t = -t ;
return 1 ;
}
inline int fabs(int x) { return x > 0 ? x : -x ; }
void dfs(int);
set<int,cmp> st ;
void nimei(int pos,int value)
{
int j , k ;
bool sth = true ;
for( j = n ; j > pos ; j--)
{
myCount[cnt[k=fabs(ans[j]-value)]]--;
if(myCount[cnt[k]]<0) sth = false ;
}
if(sth)
{
ans[pos] = value ;
dfs(pos-1);
}
for( j = n ; j > pos ; j--) myCount[cnt[fabs(ans[j]-value)]]++;
}
/*
5
9 8 7 6 6 4 3 2 2 1
*/
void dfs(int pos)
{
int i ;
if( pos == 0 )
{
int j = n-1 ;
memcpy(hb[iCount].array,ans+1,sizeof(int)*j);
sort(hb[iCount].array,hb[iCount].array+j);
if( st.count(iCount) == 0 ) st.insert(iCount++);
return ;
}
for ( i = top-1 ; i >= 1 ; i--) if(myCount[i]) break ;
if( i < 1 ) return ;
nimei(pos,dist[0]-num[i]);
nimei(pos,num[i]);
}
int main()
{
int i , j ;
myCount[0] = 0 ;
while (get(n)&&n>0)
{
iCount = 0 ;
st.clear();
memset(cnt,0,sizeof(cnt));
int maxNum = 0 ;
for(i = 0 ; i < n*(n-1)/2 ; i++)
{
get(dist[i]);
cnt[dist[i]]++;
}
for( i = 1 , top = 1 ; i <= dist[0] ; i++) if(cnt[i])
{
num[top] = i ;
myCount[top] = cnt[i] ;
cnt[i] = top++;
}
ans[n] = 0 ;
ans[n-1] = dist[0] ;
myCount[cnt[dist[0]]]--;
dfs(n-2);
set<int,cmp>::iterator ite = st.begin() ;
for( ; ite != st.end() ; ite++)
{
i = *ite ;
printf("%d",hb[i].array[0]);
for( j = 1 ; j < n-1 ; j++) printf(" %d",hb[i].array[j]-hb[i].array[j-1]);
puts("");
}
puts("-----");
}
}