洛谷 P1525 關押罪犯 ( 二分+二分圖判定) 題解
題目來源:
題目描述:
題目描述
SS城現有兩座監獄,一共關押著NN名罪犯,編號分別為1-N1−N。他們之間的關係自然也極不和諧。很多罪犯之間甚至積怨已久,如果客觀條件具備則隨時可能爆發衝突。我們用“怨氣值”(一個正整數值)來表示某兩名罪犯之間的仇恨程度,怨氣值越大,則這兩名罪犯之間的積怨越多。如果兩名怨氣值為cc 的罪犯被關押在同一監獄,他們倆之間會發生摩擦,並造成影響力為cc的衝突事件。
每年年末,警察局會將本年內監獄中的所有衝突事件按影響力從大到小排成一個列表,然後上報到S 城Z 市長那裡。公務繁忙的Z 市長只會去看列表中的第一個事件的影響力,如果影響很壞,他就會考慮撤換警察局長。
在詳細考察了NN 名罪犯間的矛盾關係後,警察局長覺得壓力巨大。他準備將罪犯們在兩座監獄內重新分配,以求產生的衝突事件影響力都較小,從而保住自己的烏紗帽。假設只要處於同一監獄內的某兩個罪犯間有仇恨,那麼他們一定會在每年的某個時候發生摩擦。
那麼,應如何分配罪犯,才能使Z 市長看到的那個衝突事件的影響力最小?這個最小值是多少?
輸入輸出格式
輸入格式:
每行中兩個數之間用一個空格隔開。第一行為兩個正整數N,MN,M,分別表示罪犯的數目以及存在仇恨的罪犯對數。接下來的MM行每行為三個正整數a_j,b_j,c_jaj,bj,cj,表示a_jaj 號和b_jbj號罪犯之間存在仇恨,其怨氣值為c_jcj。資料保證1<aj≤bj≤N ,0 < cj≤ 1,000,000,0001<aj≤bj≤N,0<cj≤1,000,000,000,且每對罪犯組合只出現一次。
輸出格式:
共11 行,為ZZ 市長看到的那個衝突事件的影響力。如果本年內監獄中未發生任何衝突事件,請輸出00。
輸入輸出樣例
輸入樣例#1: 複製
4 6 1 4 2534 2 3 3512 1 2 28351 1 3 6618 2 4 1805 3 4 12884
輸出樣例#1: 複製
3512
說明
【輸入輸出樣例說明】罪犯之間的怨氣值如下面左圖所示,右圖所示為罪犯的分配方法,市長看到的衝突事件影響力是35123512(由22 號和33 號罪犯引發)。其他任何分法都不會比這個分法更優。
【資料範圍】
對於30\%30%的資料有N≤ 15N≤15。
對於70\%70%的資料有N≤ 2000,M≤ 50000N≤2000,M≤50000。
對於100\%100%的資料有N≤ 20000,M≤ 100000N≤20000,M≤100000。
解題思路:
這題可以用並查集做,也可以用二分圖判定做,我是用二分圖做,我們二分怒氣值,保留怒氣值大於等於判斷值的邊,有bfs判斷是否是二分圖就行。
程式碼:
#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
vector<pair<int,int> >E[20005];
int ls[20005],dis[100005],n,m;
bool bfs(int x,int t)
{
queue<int>q;
q.push(t);
ls[t]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<E[now].size();i++)
{
int v=E[now][i].first;
if(!ls[v]){
if(E[now][i].second>x){
if(ls[now]==1){
ls[v]=2;
q.push(v);
}
else{
ls[v]=1;
q.push(v);
}
}
}
else{
if(E[now][i].second>x&&ls[v]==ls[now])return 0;
}
}
}
return 1;
}
bool check(int x)
{
memset(ls,0,sizeof(ls));
for(int i=1;i<=n;i++)
{
if(!ls[i]){
if(!bfs(x,i))return 0;
}
}
return 1;
}
int main()
{
memset(dis,0,sizeof(dis));
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
E[a].push_back(make_pair(b,c));
E[b].push_back(make_pair(a,c));
dis[i]=c;
}
sort(dis,dis+1+m);
int r=m,l=0,ans;
while(l<=r)
{
int mid=(l+r)/2;
if(check(dis[mid])){
ans=dis[mid];r=mid-1;
}
else l=mid+1;
}
cout<<ans<<endl;
return 0;
}