uva 1326 Jurassic Remains(中途相遇法)

來源:互聯網
上載者:User

題目連結:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=460&page=show_problem&problem=4072

題目大意:

給n個大寫字母組成的字串,選擇盡量多的串,使得每個大寫字母都能出現偶數次。

思路:

一看到Time limit: 18.000 seconds, 很high地無任何最佳化直接暴力寫了一個,9s多過了,估計是自己有史以來耗時最久的一次AC 

然後想著怎樣最佳化一下,發現所有字母出現的次數可以用二進位來表示,0表示偶數,1表示奇數。這樣的話,把所有選擇的字串狀態進行抑或運算一次,結果為0就表示全部是偶數。

這樣就從9s降到了1.692s

《競賽指南》上介紹了效率更高的“中途相遇法”: 把字串分為2部分, 首先計算前n/2個字串的所有組合得到的XOR 值,儲存在因設map中,然後在枚舉後n/2個字元,找和前面一樣的值。

// uva  1326  Jurassic Remains// 直接位元運算壓縮#include<cstdio>#include<cstring>#include<iostream>#include<cctype>using namespace std;int n;char str[30];int  st[30];bool vis[30];int dfs(int cur, int cnt, int sta){    if(cur==n){        if(!sta) return cnt;        return -1;    }    if(cur<n){        vis[cur] = true;        int res = dfs(cur+1, cnt+1, sta^st[cur]);        if(res != -1) return res;        vis[cur] = false;        res = dfs(cur+1, cnt, sta);        if(res != -1) return res;    }}int main(){    while(~scanf("%d", &n)){                memset(st, 0, sizeof(st));        for(int i=0; i<n; ++i){            scanf("%s", str);            for(int j=0; str[j]; ++j){                st[i] ^= (1<<(str[j]-'A'));            }        }        memset(vis, 0, sizeof(vis));        printf("%d\n", dfs(0, 0, 0));        bool first=true;        for(int i=0; i<n; ++i)if(vis[i]){            first ? first=false : putchar(' ');            printf("%d", i+1);        }        putchar('\n');    }    return 0;}

代碼2:中途相遇法(遞迴版本):

#include<cstdio>#include<cstring>#include<map>#include<iostream>using namespace std;const int MAXN = 30;int n, vis;int st[MAXN];char str[MAXN];map<int, int>table;map<int, int>::iterator it;int ansCnt, ansVis;inline int bitCount(int x){int cnt = 0;while(x>0){ if(x&1) ++cnt;x >>= 1;}return cnt;}void dfs1(int cur, int n, int vis, int sta){it = table.find(sta);if(it != table.end()){if(bitCount(it->second) < bitCount(vis)){it->second = vis;}}else{table[sta] = vis;}if(cur < n){dfs1(cur+1, n, vis|(1<<cur), sta^st[cur]);dfs1(cur+1, n, vis, sta);}}void dfs2(int cur, int n, int vis, int sta){it = table.find(sta);if(it != table.end()){int cnt = bitCount(vis+it->second);if(cnt > ansCnt){ansCnt = cnt;ansVis = vis+table[sta];}}if(cur < n){dfs2(cur+1, n, vis|(1<<cur),sta^st[cur]);dfs2(cur+1, n, vis, sta);}}int main(){int i,j;while(~scanf("%d", &n)){memset(st, 0, sizeof(st));table.clear();for(i=0; i<n; ++i){scanf("%s", str);for(j=0; str[j]; ++j){st[i] ^= (1<<(str[j]-'A'));}}dfs1(0, (n>>1), 0, 0);ansCnt=0, ansVis=0;dfs2(n/2, n, 0, 0);printf("%d\n", ansCnt);bool first=true;for(i=0; i<n; ++i)if((ansVis>>i)&1){first ? first=false : putchar(' ');printf("%d", i+1);}putchar('\n');}return 0;}

版本3中途相遇法(直接枚舉二進位的狀態而不用遞迴): 

#include<cstdio>#include<cstring>#include<map>#include<iostream>using namespace std;const int MAXN = 30;int n, vis;int st[MAXN];char str[MAXN];map<int, int>table;map<int, int>::iterator it;int ansCnt, ansVis;inline int bitCount(int x){    int cnt = 0;    while(x>0){ if(x&1) ++cnt;x >>= 1;  }    return cnt;}int main(){    int i,j;    while(~scanf("%d%*c", &n)){                memset(st, 0, sizeof(st));        table.clear();        for(i=0; i<n; ++i){            gets(str);            for(j=0; str[j]; ++j){                st[i] ^= (1<<(str[j]-'A'));            }        }        // 枚舉前n/2個所有組合狀態        int end = (1<<(n>>1));        for(i=0; i<end; ++i){                    int sta = 0;            for(j=0; j<(n>>1); ++j)if(i & (1<<j)){                sta ^= st[j];            }            it = table.find(sta);            if(it != table.end()){                if(bitCount(it->second) < bitCount(i)){                    it->second = i;                }            }else{                table[sta] = i;            }        }                ansCnt=0, ansVis=0;         end = (1<<(n-n/2));        for(i=0; i<end; ++i){            int sta = 0;            for(j=(n>>1); j<n; ++j)if(i & (1<<(j-(n>>1)))){                sta ^= st[j];            }            it = table.find(sta);            if(it != table.end()){                  int vis = i<<(n>>1);                int cnt = bitCount(vis+it->second);                  if(cnt > ansCnt){                      ansCnt = cnt;                      ansVis = vis+it->second;                  }              }        }        printf("%d\n", ansCnt);        bool first=true;        for(i=0; i<n; ++i)if((ansVis>>i)&1){            first ? first=false : putchar(' ');            printf("%d", i+1);        }        putchar('\n');    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.