soj4059 Towns along a Highway解题报告 经典dfs

来源:互联网 发布:nginx 域名绑定 编辑:程序博客网 时间:2024/06/05 12:46

这是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)]]++;    }/*59 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("-----");    }}


原创粉丝点击