BZOJ 1093 [ZJOI2007] 最大半連通子圖(強聯通縮點+DP)

 

題目大意php

 

題目是圖片形式的,就簡要說下題意算了html

一個有向圖 G=(V, E) 稱爲半連通的(Semi-Connected),若是知足圖中任意兩點 u v,存在一條從 u 到 v 的路徑或者從 v 到 u 的路徑ios

給一個有向圖(n 個點,m 條邊),求出她的最大半連通子圖中所包含的點數,以及這樣的最大半連通子圖有多少個(要求模上一個給定的數 x)ide

 

對於20%的數據, N 18;spa

對於60%的數據, N 10000;code

對於100%的數據, N 100000, M 1000000;htm

對於100%的數據, X 10^8。blog

 

作法分析圖片

 

這種題目在 POJ 作過相似的:POJ 2762 Going from u to v or from v to u? ,它只是詢問一個圖是不是半連通的,解題報告get

這題其實也差很少的作法,先縮點,從新建圖,使其成爲一個 DAG,DAG 中每一個點有一個點權表示這個點是原圖中的幾個點縮成的

新圖中的一個最大半連通子圖,必然是新圖中的一個最長鏈(點權和最大),知道了這點以後,DP 就好了,相似於樹形 DP,先求出從每一個點出發,能走的最長鏈是多長,統計最長的那條就是最大半連通子圖的點的數量了,至於怎麼求有多少個最大半連通子圖,也是同樣的 DP 就行,在上一步的 DP 以後,再 DP 一遍,統計每一個點出發能走出多少條最長鏈,最後統計求和便可

 

參考代碼

 

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <stack>
 5 #include <vector>
 6 #include <set>
 7 
 8 using namespace std;
 9 
10 const int N=100005;
11 
12 set <pair<int, int> > tub;
13 stack <int> S;
14 vector <int> arc[N], adj[N];
15 int n, m, x, ans1, ans2, T, ind;
16 int id[N], low[N], dfn[N], cnt[N];
17 bool vs[N];
18 
19 void tarjan(int u) {
20     dfn[u]=low[u]=T++;
21     S.push(u), vs[u]=1;
22     for(int i=0, len=(int)adj[u].size(); i<len; i++) {
23         int v=adj[u][i];
24         if(dfn[v]==-1) {
25             tarjan(v);
26             if(low[u]>low[v]) low[u]=low[v];
27         }
28         else if(vs[v] && low[u]>dfn[v]) low[u]=dfn[v];
29     }
30     if(low[u]==dfn[u]) {
31         while(1) {
32             int v=S.top();
33             S.pop(), vs[v]=0;
34             id[v]=ind, cnt[ind]++;
35             if(v==u) break;
36         }
37         ind++;
38     }
39 }
40 
41 void DFS1(int u) {
42     vs[u]=1;
43     for(int i=0, len=(int)arc[u].size(); i<len; i++) {
44         int v=arc[u][i];
45         if(!vs[v]) DFS1(v);
46         dfn[u]=max(dfn[u], dfn[v]);
47     }
48     dfn[u]+=cnt[u];
49 }
50 
51 void DFS2(int u) {
52     vs[u]=1;
53     for(int i=0, len=(int)arc[u].size(); i<len; i++) {
54         int v=arc[u][i];
55         if(!vs[v]) DFS2(v);
56         if(dfn[u]==cnt[u]+dfn[v]) id[u]=(id[u]+id[v])%x;
57     }
58     if((int)arc[u].size()==0) id[u]=1;
59     if(dfn[u]==ans1) ans2=(ans2+id[u])%x;
60 }
61 
62 int main() {
63 //    freopen("in", "r", stdin);
64     scanf("%d%d%d", &n, &m, &x);
65     for(int i=1; i<=n; i++) adj[i].clear();
66     for(int i=0, a, b; i<m; i++) {
67         scanf("%d%d", &a, &b);
68         adj[a].push_back(b);
69     }
70     fill(dfn, dfn+1+n, -1);
71     fill(vs, vs+1+n, 0);
72     T=ind=0;
73     while(!S.empty()) S.pop();
74     for(int i=1; i<=n; i++) if(dfn[i]==-1) tarjan(i);
75     for(int i=0; i<ind; i++) arc[i].clear();
76     fill(low, low+ind, 0);
77     tub.clear();
78     for(int i=1; i<=n; i++)
79         for(int j=0, len=(int)adj[i].size(); j<len; j++) {
80             int v=id[adj[i][j]], u=id[i];
81             if(u==v) continue;
82             if(tub.find(make_pair(u, v))!=tub.end()) continue;
83             low[v]++, arc[u].push_back(v);
84             tub.insert(make_pair(u, v));
85         }
86     fill(vs, vs+ind, 0);
87     fill(dfn, dfn+ind, 0);
88     ans1=0, ans2=0;
89     for(int i=0; i<ind; i++) if(low[i]==0) {
90         DFS1(i);
91         ans1=max(ans1, dfn[i]);
92     }
93     fill(vs, vs+ind, 0);
94     fill(id, id+ind, 0);
95     for(int i=0; i<ind; i++) if(low[i]==0) DFS2(i);
96     printf("%d\n%d\n", ans1, ans2);
97     return 0;
98 }
BZOJ 1093

 

題目連接 & AC 通道

 

BZOJ 1093 [ZJOI2007] 最大半連通子圖

相關文章
相關標籤/搜索