1. 程式人生 > >簡單路徑-bitset初體驗

簡單路徑-bitset初體驗

教室 zoj 輸入 ont nbsp 只需要 urn cin sca

題目描述

給定一個nn個點的無向圖,求這個圖中有多少條長度為4的簡單路徑。
n1500

輸入

第一行一個數n 接下來n行每行n個0或1 第i行第j列是1表示i與j聯通

輸出

輸出簡單路徑的個數

樣例輸入

5 00011 00000 00010 10100 10000

樣例輸出

2

提示

n<=1500

復制一下cgt大佬的ppt(未經授權hhh)

O(n^4)
不會做??
你可以離開這個教室了
暴力枚舉四個城市即可
O(n^3)
70分做法:設經過的點為a-b-c-d,枚舉中間邊b-c,再枚舉與b,c相連的點,設deg x 表示點x的度數,那麽邊b-c對答案的貢獻為(du[b]-1)(du[c]- 1) - 經過b-c這條邊的三元環個數。 計算三元環的個數只需要枚舉除b,c之外的另一個點即可,時間復雜度O(n^3)
70分算法的瓶頸在於三元環計數
那如何解決呢

so easy
我們能想到壓位
記s[i][1]為i和1~32的狀態
第x位上是1的話就說明它和x號城市有連邊
s[i][2]為i和33~64號……以此類推
i點和j點形成三元環的個數s可以這樣寫出
for k=1 ~ n/32 s=s+(s[i][k]&s[j][k] 中1的個數)
前面提到統計1的個數可以預處理出
所以時間復雜度變為了O(n^3 / 32)
n=1500時大約為1s
因此我們小小地使用了一個壓位技巧便能AC此題
題目源JZOJ4857

所以我開始了手動bitset(程序灰常的醜嚶嚶嚶)

#include<bits/stdc++.h>
using namespace std;
typedef 
long long ll; int a[1605][1605],s[1600][50],f[1605],b[66000]; int main() { int n; scanf("%d",&n); for (int i=1;i<(1<<16);i++) b[i]=b[i>>1]+(i&1); for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { scanf("%1d",&a[i][j]);
if (a[i][j]==1) { f[i]++; } } } for (int i=1;i<=n;i++) for (int j=1;j<=(n-1)/30+1;j++) for (int k=(j-1)*30+1;k<=j*30;k++) s[i][j]=(s[i][j]<<1)|a[i][k]; ll num=0; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { if (a[i][j]==1) { for (int k=1;k<=(n-1)/30+1;k++) { int xx=s[i][k]&s[j][k]; int xxx=xx>>16; xx=xx&((1<<16)-1); num=num-b[xxx]-b[xx]; } num=num+(f[i]-1)*(f[j]-1); } } printf("%lld",num); }

然而我發現c++這種神奇的東西還有美麗的bitset,於是不用白不用哈

#include<bits/stdc++.h>
using namespace std;
bitset<1600>a[1600];
int num[1600];
int main()
{
    int n;
    long long sum;
    cout<<sum;
    scanf("%d",&n);
    for (int i=0;i<n;i++) cin>>a[i];
    for (int i=0;i<n;i++) num[i]=a[i].count();
    for (int i=0;i<n;i++) 
        for (int j=0;j<n;j++) 
            if ((i!=j)&&(a[i][n-j-1]==1)) 
            {
                sum=sum+(num[i]-1)*(num[j]-1)-(a[i]&a[j]).count();
            }
    printf("%lld",sum);
    return 0;
}

是不是很簡單呢啦啦啦。

就是醬紫。

真是充實的一天哇。

還充實鞏固了RMQ

    for (int j=1;j<=20;j++)
        for (int i=1;i+(1<<j)-1<=n;i++)
            f1[i][j]=max(f1[i][j-1],f1[i+(1<<(j-1))][j-1]);
    

簡單路徑-bitset初體驗