点双连通分量——究极版。非主流的版本。。uvalive5135

来源:互联网 发布:战舞幻想曲礼物数据 编辑:程序博客网 时间:2024/05/21 14:55

这题主要是注意边界。什么事边界呢?一个单点且不是割点是边界,一个双连通分量只有一个或0个割点是边界,为什么因为他们都有一个共同点就是只能往一个方向走,当然0个割点的双联通分量是个特殊情况。然后分清边界后每个边界都必须有一个点,然后再考虑一个特殊情况,就好啦。。。

最后注意long long

实现的时候,判断割点时要注意是否是根因为这个错好久  囧!!!!

后记:为什么没用刘汝佳的代码,主要是他的代码不具有通用性,虽然常数比我的小。。。。常数什么的不管啦。。。引用经典名言:毕竟我只是个计算机科学家。。233333

#include<iostream>#include<cstdio>#include<vector>#include<stack>#include<algorithm>using namespace std;typedef long long ll;struct edgee{int from, to;};vector<int>bcc[50050];stack<edgee>stackk;edgee edge[200000];int first[100000], nextt[400000];int belong[100000], dfn[100000], low[100000],iscut[100000],countnum[100000];int edgetot = 0, deep,bcccnt;void addedge(int from, int to){//cout << "f" <<from<< endl;edge[edgetot].from = from;edge[edgetot].to = to;nextt[edgetot] = first[from];first[from] = edgetot;edgetot++;edge[edgetot].from = to;edge[edgetot].to = from;nextt[edgetot] = first[to];first[to] = edgetot;edgetot++;}void dfs(int num, int fa){dfn[num] = low[num] = deep++; int child = 0;for (int i = first[num]; i != -1; i = nextt[i]){int to = edge[i].to;if (dfn[to] == 0){child++;stackk.push(edge[i]);dfs(to, num);low[num] = min(low[to], low[num]);if (low[to] >= dfn[num]){edgee temp = stackk.top();stackk.pop();while (temp.from != edge[i].from&&temp.to != edge[i].to){belong[temp.to] = bcccnt;bcc[bcccnt].push_back(temp.to);temp = stackk.top(); stackk.pop();}if (low[to] == dfn[num])//不是桥就好办{belong[temp.from] = bcccnt, belong[temp.to] = bcccnt, bcc[bcccnt].push_back(temp.from), bcc[bcccnt].push_back(temp.to);if (fa != -1) iscut[num] = 1;//}else                                             //{if(bcc[bcccnt].size()>=1)belong[temp.to] = bcccnt,bcc[bcccnt].push_back(temp.to);//这里单点是不能进的if (fa != -1)//由于这是桥我们有两个cut不过还要注意是不是根iscut[num] = 1;if (nextt[first[to]] != -1)iscut[to] = 1;//只要还有儿子就是cut,但一定要两个以上因为有一个是父亲}if(bcc[bcccnt].size()!=0)bcccnt++;}}else{if (to != fa){low[num] = min(low[num], dfn[to]);//这我不加边的原因是避免成环}}}if (fa == -1 && child>=2)iscut[num] = 1;//是根且有两个以上的儿子}int main(){int n; int k = 1;while (scanf("%d", &n)&&n){int all = 0; edgetot = 0; deep = 1, bcccnt = 0; bcc[0].clear();while (!stackk.empty())stackk.pop();for (int i = 1; i <= n+1; i++)first[i] = -1,countnum[i]=-1;///cout << "sdsd" << endl;for (int i = 0; i < n; i++){int a, b;scanf("%d%d", &a, &b);addedge(a, b);if (countnum[a] == -1)all++, countnum[a] = 1; if (countnum[b] == -1)all++, countnum[b] = 1;  }for (int i = 1; i <= all; i++)belong[i] = -1, dfn[i] = 0, low[i] = 0,iscut[i]=0,bcc[i].clear();dfs(1, -1);ll ansnum = 0, answay = 1;for (int i = 1; i <= all; i++){if (belong[i] == -1 && iscut[i] == 0)ansnum++;//单点而且不是cut就必须有一个,然后方案是1;}for (int i = 0; i < bcccnt; i++){//if (bcc[i].size() == 1)continue;//忽略单点int cutnum = 0;for (int j = 0; j < bcc[i].size(); j++){if (iscut[bcc[i][j]]){cutnum++;}}if (cutnum == 0){ansnum += 2; answay *= ((bcc[i].size() - 1)*bcc[i].size()) / 2;}if (cutnum == 1){ansnum += 1; answay *= (bcc[i].size() - 1);}}printf("Case %d: %lld %lld\n", k, ansnum, answay);k++;}return 0;}

原创粉丝点击