這是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("-----");
}
}