hdu4635 有向圖最多添加多少邊使圖仍非強連通,hdu4635連通
思路:先縮點成有向非循環圖,則必然含有出度為0的點/入度為0的點,因為要使添加的邊盡量多,最多最多也就n*(n-1)條減去原來的m條邊,這樣是一個強連通圖,問題轉化為最少去掉幾條,使圖不強連通,原來圖中入度的點,若不添加入度,則必然不連通,同理出度為0的也一樣,所以,找入度/出度為0的點中, ki(n-ki)最小的,這裡KI是縮點後該SCC中的點數量,這個結果就是最小去掉的邊數了。
思路清晰,1A。
#include<iostream>#include<vector>#include<cstdio>#include<cstring>#include<stack>using namespace std;int n,m;const int maxv=100030;vector<vector<int> >edges(maxv);int visited[maxv]; int low[maxv]; int dfn[maxv];int ind[maxv]; int outd[maxv]; int sccnum[maxv];int scc[maxv];int num;int times;stack<int>s;int instack[maxv];void tarjan(int u){ low[u]=dfn[u]=times++; instack[u]=1; s.push(u); int len=edges[u].size(); for(int i=0;i<len;i++) { int v=edges[u][i]; if(visited[v]==0) { visited[v]=1; tarjan(v); if(low[u]>low[v])low[u]=low[v]; } else if(instack[v]&&low[u]>dfn[v]) { low[u]=dfn[v]; } } if(dfn[u]==low[u]) //在一個SCC { num++;int temp;int snum=0; do { snum++; temp=s.top(); instack[temp]=0; s.pop(); scc[temp]=num; } while(temp!=u); sccnum[num]=snum; }}void readin() //讀入資料{ scanf("%d%d",&n,&m); int a,b; for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); edges[a].push_back(b); }}void initialize(){ num=times=0; for(int i=0;i<=100000;i++) { dfn[i]=low[i]=ind[i]=outd[i]=visited[i]=sccnum[i]=scc[i]=0; edges[i].clear(); }}int solve(){ for(int i=1;i<=n;i++) if(visited[i]==0) { visited[i]=1; tarjan(i); } if(num==1){return -1;} for(int i=1;i<=n;i++) { int len=edges[i].size(); for(int j=0;j<len;j++) { int v=edges[i][j]; if(scc[v]!=scc[i]) { outd[scc[i]]++; ind[scc[v]]++; } } } int mincut=1000000000; for(int i=1;i<=num;i++) { int temp=0; if(outd[i]==0||ind[i]==0) { temp=sccnum[i]*(n-sccnum[i]); if(temp<mincut)mincut=temp; } } return n*(n-1)-m-mincut;}int main(){ int T; cin>>T;int cases=1; while(T--) { initialize(); readin(); int ans=solve(); printf("Case %d: %d\n",cases++,ans); } return 0;}
n個頂點的強連通圖至少有多少條邊?這樣的有向圖是什形狀?
強連通圖必須從任何一點出發都可以回到原處,每個節點至少要一條出路(單節點除外)
至少有n條邊,正好可以組成一個環
一個有向圖要怎添加邊,使得其成為一個強連通圖,知道要添加max(入度為0點的個數,出度為0點的個數)
15.在一個有向圖中,所有頂點的入度之和等於所有弧數和___倍。 A 、1 B、2 C、3 D、4 A 、1 在有向圖的鄰接表中,從一頂點出發的