poj 3352 Road Construction
http://poj.org/problem?id=3352
题意:给一个无向图,加上最少的边,使得改造后的图中去掉任意一条边后图依然连通。
思路:容易想到有环,则环上的点之间不会有问题,所以先首进行缩点,然后形成一棵树,记叶子数为N。再不断进行加边成环缩点可知最终结果为(N+1)/2。N=1时要特判。

#include<set> #include<map> #include<stack> #include<queue> #include<cmath> #include<bitset> #include<string> #include<climits> #include<cstdio> #include<vector> #include<utility> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define IN puts("in") #define OUT puts("out") #define FR(x) freopen(x,"r",stdin) #define FW(x) freopen(x,"w",stdout) #define MSET(x,y) memset(x,y,sizeof(x)) #define ST system("pause") using namespace std; const int maxn = 1005; struct nd { int u,v,next; }edge[maxn*2]; int head[maxn],vis[maxn],dfn[maxn],low[maxn],belong[maxn],st[maxn],in[maxn]; int ecnt,cnt,idx,tp; void add(int u,int v) { edge[ecnt].u = u; edge[ecnt].v = v; edge[ecnt].next = head[u]; head[u] = ecnt++; } void tarjan(int pre,int u) { int i,v,flag = 1; dfn[u] = low[u] = ++idx; vis[u] = 1; st[++tp] = u; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(v==pre&&flag){flag = 0; continue;} if(!dfn[v]){ tarjan(u,v); low[u] = min(low[v],low[u]); }else if(vis[u]) low[u] = min(dfn[v],low[u]); } if(dfn[u]==low[u]) { cnt++; do{ v = st[tp--]; vis[v] = 0; belong[v] = cnt; }while(v!=u); } } void processing() { int i,j,k,t,n,m,u,v; while(scanf("%d%d",&n,&m)==2) { MSET(vis,0); MSET(dfn,0); MSET(in,0); MSET(head,-1); ecnt = cnt = idx = tp = 0; for(i = 0; i < m; ++ i) { scanf("%d %d",&u,&v); add(u,v); add(v,u); } for(i = 1; i <= n; ++ i)if(!dfn[i]) tarjan(-1,i); for(i = 0; i < ecnt; ++ i) { u = belong[edge[i].u]; v = belong[edge[i].v]; if(u!=v){in[v]++; in[u]++;} } k = 0; for(i = 1; i <= cnt; ++ i) if(in[i]==2)k++; if(k==1){puts("0"); continue;} printf("%d\n",(k+1)/2); } } int main() { processing(); return 0; }