1、poj1144
题意:求割点数目。
思路:dfs
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> using namespace std; int times,root; int visit[105],flag[105]; int low[105],dfn[105]; vector <int> map[105]; int min(int a,int b) { return a<b?a:b; } void dfs(int v) { int i,w,cnum=0;//cnum 表示孩子的个数 times++; visit[v]=1; dfn[v]=low[v]=times; //记录时间戳 for(i=0;i<map[v].size();i++) { w=map[v][i]; if(!visit[w])//没有被访问过,则w是v的孩子结点 { cnum++; dfs(w); low[v]=min(low[w],low[v]); if(v==root&&cnum==2) flag[v]=1;//如果v是根,且有2个以上的孩子,则是割点 if(v!=root&&low[w]>=dfn[v]) flag[v]=1;//不为根若low[w]>=dfn[v],则是割点 } else if(v!=w) {//w已经访问过了,说明从v到w有一条回边,w是v的祖先 low[v]=min(low[v],dfn[w]); } } } int main() { int n; while(scanf("%d",&n)==1&&n) { int a,b; int i,ans=0; char c; memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(visit,0,sizeof(visit)); memset(flag,0,sizeof(flag)); for(i=0;i<=n;i++)map[i].clear(); while(scanf("%d",&a)==1&&a) { while((c=getchar())!='\n') { scanf("%d",&b); map[a].push_back(b); map[b].push_back(a); } } times=0;root=1; dfs(root); for(i=1;i<=n;i++) if(flag[i])ans++; printf("%d\n",ans); } return 0; }
题意:给n个点的有向图,问最多加多少边图仍然是非强连通图。
思路:
最后形成的图,一定是分为A部分和B部分,并且只有A向B的边没有B向A的边,为了使边数最多,AB必须都是完全图。
假设A有x个点,B有y个点,x+y=n 总边数 f=x*y+x*(x-1)+y*(y-1)=n^2-n-x*y。
那么x和y的差值越大 f越大,所以我们先将图缩点,之后找出度或入度为0的包含节点数最多的那给点作为B,剩下的点合起来作为A。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<queue> #include<vector> #include<set> #include<stack> #include<map> #include<ctime> #include<bitset> #define LL long long #define db double #define EPS 1e-8 #define inf 1e9 using namespace std; const int N = 100005; struct EDG{ int to,nxt; }e[N]; int eid,head[N]; int low[N],dfn[N],vis[N],num[N],id[N],deep,stack1[N],tn,top; int in[N],out[N]; void init(){ eid=tn=top=deep=0; memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(num,0,sizeof(num)); } void add(int u,int v){ e[eid].to=v; e[eid].nxt=head[u]; head[u]=eid++; } void tarjan(int u){ stack1[++top]=u; vis[u]=1; deep++; low[u]=dfn[u]=deep; for (int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if (vis[v]==0){ vis[v]=1; tarjan(v); low[u]=min(low[u],low[v]); } else if (vis[v]==1) low[u]=min(low[u],dfn[v]); } if (low[u]==dfn[u]){ tn++; do{ vis[stack1[top]]=2; num[tn]++; id[stack1[top]]=tn; }while (stack1[top--]!=u); } } __int64 solve(int n,int m){ __int64 ans=n*(n-1)-m; int minnum=N; for (int i=1;i<=n;i++) if (vis[i]==0) tarjan(i); if (tn==1) return -1; for (int u=1;u<=n;u++) for (int i=head[u];i!=-1;i=e[i].nxt){ int v=e[i].to; if (id[u]!=id[v]) in[id[v]]++,out[id[u]]++; } for (int i=1;i<=tn;i++) if (in[i]==0 || out[i]==0) minnum=min(minnum,num[i]); ans-=minnum*(n-minnum); return ans; } int main(){ int T,n,m,c=0,a,b; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); init(); for (int i=1;i<=m;i++){ scanf("%d%d",&a,&b); add(a,b); } printf("Case %d: %I64d\n",++c,solve(n,m)); } return 0; }
题意:构造一个以点v为割点的图。
思路:
找一个顶点只和v连,剩下的边在其余n-2个点上连,注意无法成立的条件。
代码:
#include <iostream> #include <algorithm> #include <string> #include <queue> #include <vector> #include <cmath> #include <cstdio> #include <cstring> using namespace std; const int SZ = 100002; int n, m, v; bool vis[SZ]; int main() { while(scanf("%d %d %d", &n, &m, &v) != EOF) { if(m < n - 1 || m > ((n - 2) * (n - 3)) / 2 + n - 1) puts("-1"); else if(n < 3) { puts("1 2"); } else { int u = v - 1; if(v == 1) u = 2; for(int i = 1; i <= n; i++) { if(i != v) printf("%d %d\n", i, v); } m -= (n - 1); for(int i = 1; i <= n && m; i++) { if(i == v || i == u) continue; for(int j = i + 1; j <= n && m; j++) { if(j == v || j == u) continue; printf("%d %d\n", i , j); m--; } } } } return 0; }
题意:加最少的边使原有向图边成强连通图
思路:缩点后将这些点首尾相连。
代码:
#include <cstdio> #include <vector> using namespace std; #define N 100001 int in[N], col[N]; vector<int> adj[N], beg, end; int dfs(int p)///找环 { col[p] = 1; int v = adj[p][0]; if (!col[v]) return col[p] = dfs(v); else return col[p] = p; } int main() { int n, a; while(~scanf("%d", &n)) { for (int i = 1; i <= n; ++i) { scanf("%d", &a); in[a]++; adj[i].push_back(a); } int k = 0; for (int i = 1; i <= n; ++i) { if (!in[i]) { beg.push_back(i); end.push_back(dfs(i)); ++k; } } int t = k; for (int i = 1; i <= n; ++i) { if (!col[i]) { beg.push_back(i); end.push_back(dfs(i)); ++k; } } if (k == 1 && t == 0) k = 0; printf("%d\n", k); for (int i = 0; i < k; ++i) printf("%d %d\n", end[i], beg[(i+1)%k]); } return 0; }