NOIP2010提高組複賽C 關押罪犯

2022-06-23 08:18:08 字數 2772 閱讀 7540

略這題是並查集的乙個變題,先按積怨值從大到小排序,然後乙個乙個看能否完全分開,遇到的第乙個不能分開的囚犯對(如果強行分開就必然有更高的積怨值出現)就是答案。

一開始想到的是按監獄數量弄個並查集,後來發現並不行,因為如果要分開一對囚犯,沒辦法決定誰一定住1號監獄,誰一定住2號監獄。後來試了下用囚犯數量弄並查集,發現也不行,因為沒有積怨的才能放乙個集合裡,比如1和2有積怨不在一起,3和4有積怨不在一起,那1和3,1和4等等就沒法確定,那把他們都放不同集合裡?不行,因為不在乙個集合的可能有積怨可能沒積怨。

讓後我就想當選取到i + 1對囚犯時,前i對囚犯必然也形成一張圖,這張圖可能不是連通的,換句話說,就是包含多個極大聯通子圖(囚犯小團體),小團體與小團體之間互相沒有積怨,因為程式已經選取到了i + 1對囚犯,所以這些小團體內部必然可以兩兩分開以致於沒有積怨。選取其中乙個小團體,如果這個極大聯通子圖沒有壞,那必然可以變形成如下形式:

也就是說,肯定可以一刀切。

如果有環,那促成環的這條線的兩端必分別屬於左右兩邊:

如果這個時候來了一條邊,它的兩個端點都在這張圖的一邊:

那這張圖必然怎麼切都切不開了。

也就是說,如果第i + 1對囚犯都屬於某乙個小團體的一邊,答案就出來了。

也就是說每名囚犯應該有2個狀態i和i',上面的圖應該是這樣:

於是並查集的長度應該為2n,前n個表示1~n,後n個表示1'~n'。

ps:**中並沒有判斷是否在都一邊而是直接判斷在不在乙個集合,這是因為是直接查詢的同一邊的點,就是沒有'的那邊,這樣直接判斷在不在乙個集合就可以了。

1 #include 2

using

namespace

std;34

#define rep(i,n) for (int i = 0; i < (n); ++i)

5#define for(i,s,t) for (int i = (s); i <= (t); ++i)

6#define rfor(i,t,s) for (int i = (t); i >= (s); --i)

7#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)

8#define rforeach(i,c) for (__typeof(c.rbegin()) i = c.rbegin(); i != c.rend(); ++i)910

#define pr(x) cout << #x << " = " << x << " "

11#define prln(x) cout << #x << " = " << x << endl

1213

#define all(x) x.begin(),x.end()

14#define ins(x) inserter(x,x.begin())

1516

#define ms0(a) memset(a,0,sizeof(a))

17#define msi(a) memset(a,inf,sizeof(a))

1819

#define pii pair20

#define piii pair,int>

21#define mp make_pair

22#define pb push_back

23#define fi first

24#define se second

2526 inline int

gc()

3334 inline int

ri()

4041 typedef long

long

ll;42

const

int maxn = 1e5 + 7;43

44struct

edge

48 edge(int x, int y, int

w) : x(x), y(y), w(w) {}

4950

bool

operator

< (const edge &x) const

53};

5455

intn, m, ans;

56edge e[maxn];

57int

f[maxn];

5859

int find(int

x) 63

64int

main()

73 sort(e+1, e+m+1

);74 for(i, 1, n<<1) f[i] =i;

7576 for(i, 1

, m)

84 f[x] = find(e[i].y +n);

85 f[y] = find(e[i].x +n);86}

8788 printf("

%d\n

", ans);

89return0;

90 }

view code

洛谷 關押罪犯 NOIP2010提高組複賽

s 城現有兩座監獄,一共關押著n 名罪犯,編號分別為1 n。他們之間的關係自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用 怨氣值 乙個正整數值 來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為c 的罪犯被關押在同一監獄,他...

NOIP 2010提高組題解

這是同機房一位巨佬在ak ioi之後發表的感言。為了學習他的這種精神 我太菜了,但我也想像他一樣ak ioi qaq 這篇題解就誕生了。戰車被馬拉著 直接模擬。注意入隊的時候打上標記,出隊的時候清楚標記,每次查詢的時候直接o 1 o 1 o 1 查詢標記即可。時間複雜度o n o n o n 一直在...

NOIP2010提高組 引水入城

這題。以前打的,很暴力的bfs include include using namespace std int a 502 502 ll 502 rr 502 data 300001 2 bool bz 502 502 int temp,n,m const int way 5 2 void bfs ...