soj4059 Towns along a Highway解題報告 經典dfs

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章