CodeForces - 445B - DZY Loves Chemistry-轉化問題
阿新 • • 發佈:2018-04-05
參考 define http 我們 col 只需要 它的 需要 isp
傳送門:http://codeforces.com/problemset/problem/445/B
參考:https://blog.csdn.net/littlewhite520/article/details/77018559
題意:
有N種藥劑編號 1 ~ N,然後有M種反應關系,這裏有一個試管,開始時危險系數為 1,每當放入的藥劑和瓶子裏面的藥劑發生反應時危險系數會乘以2,(註意,不管會發生反映的有幾組,只要在同一次加入的,只乘一個2;)否則就不變,給出N個藥劑和M種反應關系,求最大的危險系數。
思路:這個思路是真的優秀,感覺是一種逆向思維:
我們假設 1 ~ N 有 M 種反應關系 ,如果有反應關系的我們可以把他們看成是一個集合 ,假設這M種反應構成了 T個集合,那麽把這T個集合中的元素依次放入試管,有幾個不發生反應呢?當然是T個了,把每個集合看成是一課樹,根節點和其子節點反應,這個子節點又和它的子節點發生反應、想一想是一個鏈狀的結構、、、假設每個集合放入時先放根節點(第一個節點),那麽每個根節點是不是都不和當前試管中的藥劑發生反應呢,因為根節點只和它的子節點發生發應,而他的子節點尚未放入、、所以把這些藥劑全部放入,最少只需要 T 個不發生發應。
至於找集合的個數,可以用並查集或者dfs;
dfs的:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define pb push_back typedef long long ll; using namespace std; const int maxn = 55; vector<int>mp[maxn]; int vis[maxn]; void dfs(intView Codev) { vis[v] = 1; for(int i=0;i<mp[v].size();i++) { int tmp = mp[v][i]; if(vis[tmp]==0) { dfs(tmp); } } return ; } int main(){ int n,m; scanf("%d%d",&n,&m); memset(vis,0,sizeof(vis)); for(int i=1;i<=m;i++) {int a,b; scanf("%d%d",&a,&b); mp[a].pb(b); mp[b].pb(a); } ll ans = 1; int t = 0; for(int i=1;i<=n;i++) { if(vis[i]==0) { dfs(i); t++; } } t = n - t; for(int i=1;i<=t;i++) { ans*=2; } printf("%lld\n",ans); return 0; }
並查集:
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int maxn = 55; int n,m; int fa[maxn]; void init(){ for(int i=1;i<=n;i++) fa[i]=i; } int finx(int x) { if(fa[x]==x)return x; else return fa[x] = finx(fa[x]); } void uni(int x,int y) { int px = finx(x); int py = finx(y); if(px==py)return ; else fa[px] = py; } int main(){ scanf("%d%d",&n,&m); init(); for(int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); uni(a,b); } int t=0; for(int i=1;i<=n;i++) if(fa[i]==i)t++; t = n - t; long long ans = 1; for(int i=1;i<=t;i++) { ans *= 2; } printf("%lld\n",ans); return 0; }View Code
CodeForces - 445B - DZY Loves Chemistry-轉化問題