題目地址: http://acm.hdu.edu.cn/showPRoblem.php?pid=2062
/************************************************************************
本想用深搜(dfs),不過超時了。。無奈絞盡腦汁,用了種無奈的方法。
/********************
把他的子集畫成一個多叉樹的圖,假設圖中紅線圈起來的這一路就是答案,如果用遍歷樹的方法找到這個答案,必定超時。
那么就及早的剪枝,不符合條件的答案,直接不往下探索了,
/*********************
其實每一個結點就代表一個子集,子集就是答案。上圖假設紅色圓圈的結點就是答案,答案就是這一整條路連起來的數字。
每往下走一個結點,都篩選出正確的唯一一條分支。
/****************************************************************
代碼如下:
/********************
#include<stdio.h>#include<algorithm>using namespace std;long long c[21]={0,1},j,n; //j用來統計當前走到哪里了int m;void swap(int &a,int &b)//c++中的引用,實現值得交換{ int temp=a; a=b; b=temp;}void po(int a[],int begen){ if(j>=n||begen>m) { printf("%d",a[1]); for(int i=2;i<begen;i++) printf(" %d",a[i]); puts(""); return; } long long t=j;//用t暫時記錄下j for(int i=begen;i<=m;i++) { if(i-begen+1==(n-t-1)/(c[m-begen]+1)+1)//判斷條件很復雜,意思是檢索到有答案的那一個分支時,就執行下面 { j++; //printf("樹的路徑:**%3d ** i:%3d,begen:%3d** /n",i-begen+1,i,begen); swap(a[i],a[begen]); //選擇a[i]這個數字,把它交換到第begen的位置 sort(a+begen+1,a+m+1); //對剩下的數字排序(字典序,從小到大) po(a,begen+1); //遞歸,尋找下一個數字,排到(數組a中)begen+1的位置 break;//以后的路都不符合了,直接break; } else j+=c[m-begen]+1;//統計走到第多少個子集了 }}int main(){ int a[21]={0,1}; for(long long i=2;i<=20;i++) c[i]=i*(c[i-1]+1); while(~scanf("%d%lld",&m,&n)) { for(int i=1;i<=m;i++) a[i]=i; j=0; po(a,1); } return 0;}
|
新聞熱點
疑難解答