poj 5943 Kingdom of Obsession (二分圖匹配+素數間隔小知識)
阿新 • • 發佈:2018-11-25
題目連結:poj 5943
題意:給定n,s,現在讓1-n和s+1,s+2...s+n這兩堆數匹配,如果(s+i)%j==0那麼s+i就可以和j構成一個匹配,求是否能讓所有的n個數字都構成匹配。
題解:首先我們看到匹配,就應該先想到是不是關於二分圖匹配的問題?顯然這是的,但因為n太大,會T和超記憶體,那麼我們可以想下怎麼去優化,通過打表我們可以知道在1e9範圍,兩素數直接的間隔不超過300,網上有論文說不超過246,隨便啦,不影響我們最後的結果,所以答案就出來了,當n大於300時,直接輸出No,因為此時素數肯定至少有兩個,又因為素數只能被1和本身整除,而此時元素值又大於位置值,故位置1只能被一個素數放,相應的另外一個就放不了了。
此時還有個特殊情況,當n>s時,故有些位置值等於某元素值,那麼我們就可以將這些特殊的就放一起,這樣就會出現兩個素數存在但還會有解的情況,例如 n=5 s=4,->5 6 7 8 9 ,5和7是素數,但5可以直接放在位置5,故也不影響結果。
所以這時我們交換下n和s就行了。
#include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; const int maxn=500; vector<int> G[maxn]; int match[maxn]; bool check[maxn]; bool dfs(int u) { int item=G[u].size(); for(int i=0;i<item;i++) { int v=G[u][i]; if(!check[v]){ check[v]=1; if(match[v]==-1||dfs(match[v])){ match[v]=u; return 1; } } } return 0; } int hungarian(int num_left) { int ans=0; memset(match,-1,sizeof(match)); for(int u=1;u<=num_left;u++) { memset(check,0,sizeof(check)); if(dfs(u)) ans++; } return ans; } int main() { int ncase; scanf("%d",&ncase); for(int T=1;T<=ncase;T++) { int n,s; scanf("%d%d",&n,&s); if(n>s) swap(n,s); if(n>300){ printf("Case #%d: No\n",T);continue; } for(int i=1;i<=n;i++) G[i].clear(); for(int i=1;i<=n;i++) { int item=s+i;///元素值 for(int j=1;j<=n;j++){ ///位置 if(item%j==0) G[j].push_back(i); } } int sum=hungarian(n); if(sum==n){ printf("Case #%d: Yes\n",T); } else{ printf("Case #%d: No\n",T); } } return 0; }