1. 程式人生 > 其它 >洛谷-關押罪犯

洛谷-關押罪犯

技術標籤:並查集洛谷

題目描述:
S 城現有兩座監獄,一共關押著 NN 名罪犯,編號分別為 1-N1−N。他們之間的關係自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用“怨氣值”(一個正整數值)來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為 cc 的罪犯被關押在同一監獄,他們倆之間會發生摩擦,並造成影響力為 cc 的衝突事件。
每年年末,警察局會將本年內監獄中的所有衝突事件按影響力從大到小排成一個列表,然後上報到 S 城 Z 市長那裡。公務繁忙的 Z 市長只會去看列表中的第一個事件的影響力,如果影響很壞,他就會考慮撤換警察局長。

在詳細考察了NN 名罪犯間的矛盾關係後,警察局長覺得壓力巨大。他準備將罪犯們在兩座監獄內重新分配,以求產生的衝突事件影響力都較小,從而保住自己的烏紗帽。假設只要處於同一監獄內的某兩個罪犯間有仇恨,那麼他們一定會在每年的某個時候發生摩擦。
那麼,應如何分配罪犯,才能使 Z 市長看到的那個衝突事件的影響力最小?這個最小值是多少?
輸入格式:
在這裡插入圖片描述
輸出格式:
在這裡插入圖片描述
輸入樣例:

4 6
1 4 2534
2 3 3512
1 2 28351
1 3 6618
2 4 1805
3 4 12884

輸出樣例:

3512

思路:
運用並查集的思想寫這道題目。首先我們將影響力由大到小排序。找出必須關在一起的兩個人的最大的影響力。做法:如果這個人沒有敵人,就記錄下當下他的敵人。如果這個人已經記錄了敵人,就將他當前的敵人和記錄的敵人關在一起,即他們的“祖先”是一個。並且作為敵人的兩個人都要做上述的判斷和記錄。因為可能存在兩人種的一人已經有敵人了,而另外一個人沒有記錄的敵人。最後注意特別的0就ok了。

注意事項:
當出現RE的時候不要只關注演算法的時間複雜度,還要關注我們開的陣列的大小問題(尤其是當我們認為我們的演算法思路足夠精簡巧妙的時候)。
AC程式碼:

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int f[20005],a[20005];
typedef struct Node{
    int x,y,z;
}node;
node p[100005];
inline bool cmp(node a,node b){
    return a.z>b.
z; } inline int fin(int m){ if(m==f[m]){ return m; } else{ f[m]=fin(f[m]); return f[m]; } } inline void hp(int x,int y){ int f1=fin(x),f2=fin(y); f[f1]=f2; } inline bool check(int x,int y){ int f1=fin(x),f2=fin(y); if(f1==f2){ return true; } else{ return false; } } int main(){ int n,m; //cin>>n>>m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ f[i]=i; } for(int i=0;i<m;i++){ // cin>>p[i].x>>p[i].y>>p[i].z; scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z); } sort(p,p+m,cmp); int ans=0; for(int i=0;i<m;i++){ if(check(p[i].x,p[i].y)){ ans=p[i].z; break; } else{ if(!a[p[i].x]){ a[p[i].x]=p[i].y; } else{ hp(f[a[p[i].x]],p[i].y); } if(!a[p[i].y]){ a[p[i].y]=p[i].x; } else{ hp(f[a[p[i].y]],p[i].x); } } } // cout<<ans; printf("%d",ans); return 0; }