1. 程式人生 > >牛客練習賽26 C 城市規劃【思維】

牛客練習賽26 C 城市規劃【思維】

城市規劃

時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 262144K,其他語言524288K 64bit IO Format: %lld

題目描述

小a的國家裡有n個城市,其中第i和第i - 1個城市之間有無向道路連線,特殊的,第1個城市僅與第2個城市相連

為了減輕道路維護負擔,城市規劃局局長MXT給出了m個要求,他想讓小a斷開一些道路,使得任意1 ≤ i ≤ m ,城市xi不能到達城市yi

同時最小化斷開道路的數量。

輸入描述:

第一行兩個整數n, m,分別表示城市的數量和請求的數量
接下來m行,每行兩個整數x,y,表示需要使得x不能到達y

輸出描述:

輸出一個整數,表示最小斷開橋的數量

示例1

輸入

4 2
1 3
2 4

輸出

1

說明

可以斷開(2, 3)城市之間的道路

示例2

輸入

4 3
1 3
2 4
1 2

輸出

2

說明

可以斷開(1, 2) (2, 3)之間的道路

備註:

對於100%的資料:n ≤ 106, m ≤ 107 本題不卡常數,請設計嚴格線性做法

讀入檔案較大,請使用讀入優化,本機除錯時請使用檔案輸入輸出 #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++) char buf[(1 << 22)], *p1 = buf, *p2 = buf; inline int read() {     char c = getchar(); int x = 0, f = 1;     while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();     return x * f; } 用法: int a = read(), b = read(); std::cout << a + b;

由於nowcoder的編譯器限制,如果需要在程式中開107級別的陣列,可能會出現記憶體超限的情況,請使用new函式手動申請 用法: int* P = new int[(int)1e7 + 10];

題解:首先需要讀入優化。程式flag[y]標記結點y是否在查詢中出現,pos[y]記錄要使y和對應的x斷開至少要從什麼位置之後斷開一條邊,例如x和y分別為1和4,那麼pos[4]=1表明至少要從1編號之後選擇一條邊,由於y值可能相同,因此程式有取pos[y]的較大值的操作。l 記錄上次斷掉的邊的位置,初始化為0,對於當前的y如果pos[y]>=l表明必須再斷掉一條邊才能滿足x和y不連通,此時更新答案和l的值

AC的C++程式碼:

#include<iostream>

using namespace std;

//讀入優化 
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<22,stdin),p1 == p2)?EOF:*p1++)
char buf[(1<<22)],*p1=buf,*p2=buf;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c == '-') f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c = getchar();}
    return x * f;
}

const int N=1000010;
bool flag[N];//標記y出現的位置 
int pos[N];//pos[y]記錄要使得y和對應的x斷開至少要在哪個結點編號 

int main()
{
	int n,m,x,y;
	n=read(),m=read();
	while(m--){
		x=read();
		y=read();
		flag[y]=true;
		pos[y]=max(pos[y],x); 
	}
	//線性掃描
	int l=0,ans=0;
	for(int i=1;i<=n;i++)
	  if(flag[i]&&pos[i]>=l){
	  	l=i;
	  	ans++;
	  } 
	printf("%d\n",ans);
	return 0;
}