1. 程式人生 > >牛客網提高組模擬賽第七場 T3 洞穴(附bitset介紹)

牛客網提高組模擬賽第七場 T3 洞穴(附bitset介紹)

main \n std 個數 fin 輸出 1的個數 define 聲明

技術分享圖片
技術分享圖片
技術分享圖片

就是DP。

我們可以很簡單的想到要枚舉中間點,進行邊數的轉移。

但是因為邊長數據範圍很大,所以我們考慮log的倍增。

狀態設計為\(dp[i][j][k]\),為從節點\(i\)\(2^k\)步能否走到節點\(j\)。但是我們發現這樣不好轉移狀態(其實是我不太會啊)

正解是狀態壓縮,但是因為\(n\)有點大,所以這裏介紹一個黑科技:\(bitset\)

bitset只能存儲0或1,但是較bool來說空間更優,一個元素只占一個bit,而且其中的每個元素都可以被單獨訪問或者修改——比如說訪問s的第一位,直接\(s[1]\)即可。

  • bitset的聲明:
bitset<10(長度)>s(變量名);
  • bitset可以被直接賦值:
s=101;
//存儲為0001100101
  • bitset的輸出:
cout<<s<<endl;
//0001100101
cout<<s.to_ulong()<<endl;
//101
  • bitset支持位運算;
  • bitset的其他功能支持:(轉)
a.size()      返回大小(位數)
a.count()     返回1的個數
a.any()       返回是否有1
a.none()      返回是否沒有1
a.set()       全都變成1
a.set(p)      將第p+1位變成1
a.set(p, x)   將第p+1位變成x
a.reset()     全都變成0
a.reset(p)    將第p+1位變成0
a.flip()      全都取反
a.flip(p)     將第p+1位取反
a.to_ulong()  返回它轉換為unsigned long的結果,如果超出範圍則報錯
a.to_ullong() 返回它轉換為unsigned long long的結果,如果超出範圍則報錯
a.to_string() 返回它轉換為string的結果

之後我們就可以用bitset壓位了。

狀態設計為\(dp[i][j][k]\)\(i\)為走\(2^i\)個單位長度,\(j\)為出發節點,\(k\)為以\(j\)為出發節點,走\(2^i\)個單位長度是否能夠走到其他節點的狀態。(1為可以走到)

之後狀態轉移就是如果\(dp[i][j][k]==1\),那麽\(dp[i+1][j]|=dp[i][k]\)。這個是預處理節點與節點之間走多少能夠到達的過程。

然後查詢時另開一個新的bitset:ans來記錄當前能夠走到的節點,然後把\(len\)二進制化,顯然我們從起點走,把二進制下的\(len\)每走一位能夠到達的節點全都記錄下來,然後再用它們進行轉移就可以了。

代碼如下:

#include<iostream>
#include<algorithm>
#include<bitset>
#include<cstdio>
#define MAXN 110
using namespace std;
int n,m,q;
bitset<MAXN>dp[40][MAXN];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        dp[0][x][y]=1;
    }
    for(int i=0;i<=31;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                if(dp[i][j][k])
                    dp[i+1][j]|=dp[i][k];
    scanf("%d",&q);
    while(q--)
    {
        int len,from,to;
        scanf("%d%d%d",&len,&from,&to);
        bitset<MAXN>ans;
        ans.reset();
        ans[from]=1;
        for(int i=0;i<=31;i++)
        {
            if(len&(1<<i))
            {
                bitset<MAXN>cur;
                cur.reset();
                for(int j=1;j<=n;j++)
                {
                    if(ans[j])
                        cur|=dp[i][j];
                }
                ans=cur;
            }
        }
        if(ans[to]) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

牛客網提高組模擬賽第七場 T3 洞穴(附bitset介紹)