[链式向前星][二分查找][二分图] 关押罪犯

关押罪犯

原题链接
Description

S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件。

每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。

在详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。

那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?

Input

输入文件名为 prison.in。

输入文件的每行中两个数之间用一个空格隔开。

第一行为两个正整数 N 和 M,分别表示罪犯的数目以及存在仇恨的罪犯对数。

接下来的 M 行每行为三个正整数 aj,bj,cj,表示 aj 号和 bj 号罪犯之间存在仇恨,其怨气值为 cj。数据保证1 ≤ a j < b j ≤ N ,0 < c j ≤ 1,000,000,000 ,且每对罪犯组合只出现一 次。

Output

输出文件 prison.out。

共 1 行,为 Z 市长看到的那个冲突事件的影响力。如果本年内监狱 中未发生任何冲突事件,请输出 0。

Sample Input

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

3512


考虑二分答案加check的解答。
分析:
check函数部分:遍历所有的边,如果边的权值大于mid,则进行二分图染色,如果小于等于mid,则不操作,因为他们可能颜色一样,可能颜色不一样。

遍历图的部分:这是一个无向有权图,要dfs遍历这个图,考虑使用链式向前星的方法记录图。(邻接表遍历比较吃力,邻接矩阵比较占空间和时间)。

有关于二分图检查和链式向前星的实现,读者可自己搜索


#include
#include
#include
#include
using namespace std;
const int  maxn = 2000000;
int head[maxn], w[maxn], color[maxn];
struct node {
    int to, w, next; // 边的终点,权值,与当前边同起点的下一条边的地址
}mmap[maxn];
int n, m, cnt, key;
void insert(int a, int b, int c) {
    mmap[++cnt].to = b;
    mmap[cnt].w = c;
    mmap[cnt].next = head[a];
    head[a] = cnt;
}
bool dfs(int v, int c) {
    color[v] = c;
    for (int i = head[v]; i != 0; i = mmap[i].next) {
        if (mmap[i].w > key) {
            if (color[mmap[i].to] == c)  return false;
            if (color[mmap[i].to] == 0 && !dfs(mmap[i].to, -c)) return false;
        }
    }
    return true;
}
bool test(int mid) {
    memset(color, 0, sizeof color);
    key = w[mid];
    for (int i = 1; i <= n; i++) {
        if (color[i] == 0) {
            if (!dfs(i, 1)) {
                return false;
            }
        }
    }
    return true;
}
int main () {
    cin >> n >> m;
    int a, b, c;
    for (int i = 1; i <= m; i++) {
        cin >> a >> b >> c;
        insert(a, b, c);
        insert(b, a, c);
        w[i + 1] = c;
    }
    w[1] = 0;
    sort(w + 1, w + m + 1);
    int l = 1, r = m + 1, mid;
    while(l < r) {
        mid = (l + r) / 2;
        if (test(mid)) r = mid;
        else l = mid + 1;
    }
    cout << w[l];
    return 0;
}

你可能感兴趣的:([链式向前星][二分查找][二分图] 关押罪犯)