雙指針,BFS與圖論(一)

(一)雙指針css

1.日誌統計ios

小明維護着一個程序員論壇。如今他收集了一份」點贊」日誌,日誌共有 N 行。nginx

其中每一行的格式是:程序員

ts id 

表示在 ts 時刻編號 id 的帖子收到一個」贊」。編程

如今小明想統計有哪些帖子曾經是」熱帖」。數組

若是一個帖子曾在任意一個長度爲 D 的時間段內收到很多於 K 個贊,小明就認爲這個帖子曾是」熱帖」。bash

具體來講,若是存在某個時刻 T 知足該帖在 [T,T+D) 這段時間內(注意是左閉右開區間)收到很多於 K個贊,該帖就曾是」熱帖」。oop

給定日誌,請你幫助小明統計出全部曾是」熱帖」的帖子編號。ui

輸入格式

第一行包含三個整數 N,D,K
spa

如下 N 行每行一條日誌,包含兩個整數 ts 和 id

輸出格式

按從小到大的順序輸出熱帖 id

每一個 id 佔一行。

數據範圍

1KN105,
0ts,id105,
1D10000

輸入樣例:

7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3

輸出樣例:

1
3
解題思路:排序+雙指針
①對全部的贊按時間排序
②經過雙指針i,j維護長度不大於d的區間,並記錄該帖子中的獲贊數
#include<iostream>
#include<algorithm>
#include<cstdio>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N=100010;
int n,d,k;
int cnt[N];
bool ts[N];
PII flags[N];
int main()
{
    int i,j;
    scanf("%d%d%d",&n,&d,&k);
    for(i=0;i<n;i++)
        scanf("%d%d",&flags[i].x,&flags[i].y);
    sort(flags,flags+n);
    for(i=0,j=0;i<n;i++)
    {
        int id=flags[i].y;
        cnt[id]++;

        while(flags[i].x-flags[j].x>=d)
        {
            cnt[flags[j].y]--;
            j++;
        }
        if(cnt[id]>=k)
            ts[id]=true;
    }
    for(i=0;i<=100000;i++)
    {
        if(ts[i])
            printf("%d\n",i);
    }
    return 0;
}

 

(二)BFS
1.獻給阿爾吉儂的花束

阿爾吉儂是一隻聰明又慵懶的小白鼠,它最擅長的就是走各類各樣的迷宮。

 

今天它要挑戰一個很是大的迷宮,研究員們爲了鼓勵阿爾吉儂儘快到達終點,就在終點放了一塊阿爾吉儂最喜歡的奶酪。

 

如今研究員們想知道,若是阿爾吉儂足夠聰明,它最少須要多少時間就能吃到奶酪。

 

迷宮用一個 R×C 的字符矩陣來表示。

 

字符 S 表示阿爾吉儂所在的位置,字符 E 表示奶酪所在的位置,字符 # 表示牆壁,字符 . 表示能夠通行。

 

阿爾吉儂在 1 個單位時間內能夠從當前的位置走到它上下左右四個方向上的任意一個位置,但不能走出地圖邊界。

 

輸入格式

 

第一行是一個正整數 T,表示一共有 T 組數據。

 

每一組數據的第一行包含了兩個用空格分開的正整數 R 和 C,表示地圖是一個 R×C 的矩陣。

 

接下來的 R 行描述了地圖的具體內容,每一行包含了 C 個字符。字符含義如題目描述中所述。保證有且僅有一個 S 和 E。

 

輸出格式

 

對於每一組數據,輸出阿爾吉儂吃到奶酪的最少單位時間。

 

若阿爾吉儂沒法吃到奶酪,則輸出「oop!」(只輸出引號裏面的內容,不輸出引號)。

 

每組數據的輸出結果佔一行。

 

數據範圍

 

1<T10,
2R,C200

 

輸入樣例:

 
3
3 4
.S.. ###. ..E. 3 4 .S.. .E.. .... 3 4 .S.. #### ..E. 
 

輸出樣例:

 
5
1
oop!
解題思路:要求最短的距離,應該用BFS來進行求解,咱們須要map數組來存儲地圖,同時定義一個pair數組來存儲當前或者下一步的位置,
在定義一個vis數組來記錄走的步數及是否走過該條路,每進行一次bfs都要對vis數組進行初始化。
代碼:
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N=210;
int x[]={1,-1,0,0};
int y[]={0,0,1,-1};
int t,r,c;
char map[N][N];
int vis[N][N];

bool check(int X,int Y)
{
    if(X<0||X>=r||Y<0||Y>=c)
        return false;
    if(map[X][Y]=='#')
        return false;
    if(vis[X][Y]!=0)
        return false;
    return true;
}
int bfs(int bx,int by)
{
    queue<PII> q;
    memset(vis,0,sizeof(vis));
    vis[bx][by]=0;
    PII m;
    m.x=bx,m.y=by;
    q.push(m);
    while(q.size())
    {
        PII tem=q.front();
        if(map[tem.x][tem.y]=='E')
            return vis[tem.x][tem.y];
        q.pop();
        for(int i=0;i<4;i++)
        {
            int X=tem.x+x[i];
            int Y=tem.y+y[i];
            if(check(X,Y)==false)
                continue;
            vis[X][Y]=vis[tem.x][tem.y]+1;
            PII tem2;
            tem2.x=X,tem2.y=Y;
            q.push(tem2);
        }
    }
    return 0;
}
int main()
{
    int i,j,bx,by;
    cin>>t;
    while(t--)
    {
        cin>>r>>c;
        for(i=0;i<r;i++)
        {
            for(j=0;j<c;j++)
            {
                cin>>map[i][j];
                if(map[i][j]=='S')
                {
                    bx=i;
                    by=j;
                }
            }
        }
        int k=bfs(bx,by);
        if(k)
        {
            cout<<k<<endl;
        }
        else
            cout<<"oop!"<<endl;
    }
    return 0;
}
 

2.紅與黑

有一間長方形的房子,地上鋪了紅色、黑色兩種顏色的正方形瓷磚。

你站在其中一塊黑色的瓷磚上,只能向相鄰(上下左右四個方向)的黑色瓷磚移動。

請寫一個程序,計算你總共可以到達多少塊黑色的瓷磚。

輸入格式

輸入包括多個數據集合。

每一個數據集合的第一行是兩個整數 W 和 H,分別表示 x 方向和 y 方向瓷磚的數量。

在接下來的 H 行中,每行包括 W 個字符。每一個字符表示一塊瓷磚的顏色,規則以下

1)‘.’:黑色的瓷磚;
2)‘#’:白色的瓷磚;
3)‘@’:黑色的瓷磚,而且你站在這塊瓷磚上。該字符在每一個數據集合中惟一出現一次。

當在一行中讀入的是兩個零時,表示輸入結束。

輸出格式

對每一個數據集合,分別輸出一行,顯示你從初始位置出發能到達的瓷磚數(記數時包括初始位置的瓷磚)。

數據範圍

1W,H20

輸入樣例:

6 9 
....#. .....# ...... ...... ...... ...... ...... #@...# .#..#. 0 0 

輸出樣例:

45
解題思路:咱們的目的是讓交換的次數最少,看下圖

 

 根據數字和對應的下標,將該數字與應該在的下標的數字相連,構成一個環,咱們的目的是讓每一個數字自成一個環。

當咱們進行同環內的兩個數交換時:裂成兩個環

當進行不是同環內的交換時:會將兩個環合併成一個環

假設初始的環個數爲k,咱們要將他變成n個自環,咱們須要至少n-k步操做

所以,對於本題的解法就是找出初始的環數

代碼:

#include<iostream>
using namespace std;
const int N=10010;
int a[N];
bool tr[N];
int main()
{
    int i,j,n;
    int ans=0;
    cin>>n;
    for(i=1;i<=n;i++)
        cin>>a[i];
    for(i=1;i<=n;i++)
    {
        if(!tr[i])
        {
            ans++;
            for(j=i;!tr[j];j=a[j])
                tr[j]=true;
        }
    }
    cout<<n-ans<<endl;
    return 0;
}
相關文章
相關標籤/搜索