[NOIP2010]关押罪犯(二分+二分图染色)

来源:互联网 发布:淘宝卖家温馨寄语 编辑:程序博客网 时间:2024/05/18 16:13

传送门
大意:我们把图分为两部分,使得两部分中的内部边的最大权值最小。
思路:哎,拿到题的时候想了二分图染色,发现不好做,但我没有想到二分,只好最后去骗了一个30分。正确的思路是:首先我们要 去二分最大的冲突边的是哪一条(按照权值二分),因为当二分的边权增大时,连的边也就越少,连通块的数目就越多,冲突就越少,所以边权是可以二分的,在二分过后用二分图判定,如果可以染成二分图即为可行的解。

代码:

#include<cstdio>#include<algorithm>#include<cstring>#define MAXM 100005#define MAXN 20005using namespace std;int col[MAXN], n, m;struct node{    int v, w;    node *next;}Edge[MAXM * 2], *Adj[MAXN], *Mcnt = Edge;struct E{    int u, v, w;    bool operator < (const E rhs) const    {        return w < rhs.w;    }}e[MAXM];void Addedge(int u, int v, int w){    node *t = ++Mcnt;    t->v = v;    t->w = w;    t->next = Adj[u];    Adj[u] = t;}int ans, mid;bool dfs(int u, int fa){    if(col[u] != -1 && col[u] == col[fa]) return 0;    if(col[u] == !col[fa]) return 1;    col[u] = !col[fa];    for(node *p = Adj[u]; p; p = p->next)        if(p->v != fa)            if(p->w > e[mid].w)                if(!dfs(p->v, u))                    return 0;    return 1;}int main(){    scanf("%d%d", &n, &m);    int l = 0, r = m;    for(int i = 1; i <= m; i ++)        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);    sort(e + 1, e + m + 1);    for(int i = 1; i <= m; i ++)    {        Addedge(e[i].u, e[i].v, e[i].w);        Addedge(e[i].v, e[i].u, e[i].w);    }    while(l <= r)    {        mid = (l + r) >> 1;        memset(col, -1, sizeof(int) * (n+2));        col[0] = 0;        bool flag = 0;        for(int i = 1; i <= n; i ++)            if(col[i] == -1)                if(!dfs(i, 0))                {                    flag = 1;                    break;                }        if(flag) l = mid + 1;        else {ans = e[mid].w; r = mid - 1;}    }    printf("%d\n", ans);    return 0;}
0 0
原创粉丝点击