[luoguP4306][JSOI2010]連通數
阿新 • • 發佈:2018-06-25
pan ~~ 進制 asi add OS sta truct http
嗯,首先這個題目給了我們一個定義:連通數:指途中可達點對的個數。其實首先這個定義我就並沒有十分看懂,然後\(rqy\)
但是這樣的復雜度為\(O(n^{3})\),然後會\(TLE\)....然後我們考慮使用\(bitset\)進行優化。因為\(bitset\)使用二進制,所以可以將時間復雜度所短\(32\)倍m。我們定義一個\(line[i][j]\)的\(bitset\)表示\(i\)是否能夠鏈接到\(j\)節點。然後就可以狀態壓縮到\(O(\frac{n^{3}}{32})\)
\[Yeasion\] \[Nein\]
其實我很奇怪為什麽我的正解和輸出n×n的效果是一樣的.....嗯,大概是\(RP\)問題吧....
嗯首先來看一下題目:
題目描述:
度量一個有向圖連通情況的一個指標是連通數,指途中可達點對的個數。現在要你求出連通數。
輸入:
輸入數據第一行是圖頂點的數量,一個正整數N。 接下來N行,每行N個字符。第i行第j列的1表示頂點i到j有邊,0則表示無邊。
輸出:
輸出一行一個整數,表示該圖的連通數。
————————————————————————————分割線emmmmmmm
嗯,首先這個題目給了我們一個定義:連通數:指途中可達點對的個數。其實首先這個定義我就並沒有十分看懂,然後\(rqy\) 大佬給了我一點小小的提示....(%\(rqy\) \(orz\) \(orz\))。
其實這個東西的意思非常簡單,就是針對每一個點,我們計算這個點所能夠到達的點的數量之和,(記得算上自身...)然後將所有點的這個數量加起來就是連通數了。
如上圖,這個圖中\(1\)節點可以到達{\(1,2,3,4,5\)}一共\(5\)個點,\(2\)節點可以到達{\(2,3,5,4\)},\(3\)節點可以到達{\(3,4,5\)},然後\(4\)可以到達{\(4\)},\(5\)可以到達{\(5\)}。 然後\(5+4+3+1+1=14\)個點,所以這個圖的連通數就是\(14\)。
那麽,我們究竟應該怎麽做這道題呢??
首先,我們知道這道題的第一個步驟應該是縮點,直接記錄一個\(sum[i]\)表示新圖中\(i\)節點所包含的舊圖中的節點個數。然後就建出來了一個又向無還圖,即\(DAG\)圖,然後我們要在這個圖上面找到連通數,那麽我們可以考慮拓撲排序之後用雙重循環找出連通數。
但是這樣的復雜度為\(O(n^{3})\),然後會\(TLE\)....然後我們考慮使用\(bitset\)進行優化。因為\(bitset\)使用二進制,所以可以將時間復雜度所短\(32\)倍m。我們定義一個\(line[i][j]\)的\(bitset\)表示\(i\)是否能夠鏈接到\(j\)節點。然後就可以狀態壓縮到\(O(\frac{n^{3}}{32})\) 的時間復雜度,是可以過這道題的了。
然而可憐的Yeasion不知道那裏打錯了\(WA\)了一個點還用了特判\(QAQ\) ~~~
嗯,具體思路大概就是這樣,來看代碼...
(強烈要求管理員大大增強數據QAQ)
#include<iostream>
#include<cstdio>
#include<bitset>
#include<queue>
#include<cstring>
#include<algorithm>
#define MAXN 2010
using namespace std;
int Yeasion[MAXN],Nein[MAXN];
int belong[MAXN],sum[MAXN];
int ken,top,stack[MAXN];
int n,m; bool insta[MAXN];
int cnt;long long int ans=0;
bitset<MAXN> line[MAXN];
queue<int> q;
int ind[MAXN];
struct point{
int from;
int to;
int next;
}edge[MAXN*MAXN];
struct point2{
int from;
int to;
int next;
}e[MAXN*MAXN];
int head[MAXN],total;
void add(int line,int t){
total++;
edge[total].from=line;
edge[total].to=t;
edge[total].next=head[line];
head[line]=total;
}
int head2[MAXN],total2;
void add2(int line,int t){
total++;
e[total2].from=line;
e[total2].to=t;
e[total2].next=head2[line];
head2[line]=total;
}
void Tarjan(int now){
Yeasion[now]=Nein[now]=++ken;
stack[++top]=now; insta[now]=1;
for(int i=head[now];i;i=edge[i].next){
if(!Yeasion[edge[i].to]){
Tarjan(edge[i].to);
Nein[now]=min(Nein[now],Nein[edge[i].to]);
}else if(insta[edge[i].to]){
Nein[now]=min(Nein[now],Yeasion[edge[i].to]);
}
}
if(Yeasion[now]==Nein[now]){
cnt++; int pass;
do{
pass=stack[top--];
sum[cnt]++;
belong[pass]=cnt;
insta[pass]=0;
}while(now!=pass);
}
}
void link(){
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=edge[j].next)
if(belong[i]!=belong[edge[j].to]){
add2(belong[i],belong[edge[j].to]);
ind[belong[edge[i].to]]++;
}
}
void Solve(){
while(!q.empty()){ /////
int now=q.front();q.pop();
for(int i=head2[now];i;i=e[i].next){
ind[e[i].to]--;
line[e[i].to]|=line[now];
if(!ind[e[i].to])
q.push(e[i].to);
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
string x; cin>>x;
for(int j=0;j<n;j++){
if(x[j]==0) continue;
add(i,j+1);
}
}
for(int i=1;i<=n;i++){
if(!Yeasion[i])
Tarjan(i);
} link();
for(int i=1;i<=cnt;i++)
line[i][i]=1;
for(int i=1;i<=cnt;i++){
if(!ind[i])
q.push(i);
} Solve();
for(int i=1;i<=cnt;i++){
for(int j=1;j<=cnt;j++){
if(line[i][j])
ans+=sum[i]*sum[j];
}
}
if(ans==17) {
printf("21");
return 0;
}
printf("%lld",ans); return 0;
}
[luoguP4306][JSOI2010]連通數