【noip2010】关押罪犯

题目描述

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

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

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

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

输入输出格式

输入格式:
输入文件的每行中两个数之间用一个空格隔开。第一行为两个正整数N 和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。接下来的M 行每行为三个正整数aj,bj,cj,表示aj 号和bj 号罪犯之间存在仇恨,其怨气值为cj。数据保证1



#include
#include
using namespace std;
const int MAXN=20001;
const int MAXM=100001;
int n,m,father[MAXN],enemy[MAXN];
struct Edge{
    int from,to,dis;
}edge[MAXM];

int find(int x)
{
    if (father[x]!=x) return father[x]=find(father[x]);
    return father[x];
}

void unionn(int x,int y)
{
    int xx=find(x);
    int yy=find(y);
    if (xx!=yy) father[xx]=father[yy];
}

bool judge(int x,int y)
{
    return find(x)==find(y);
}

bool comp(Edge a,Edge b)
{
    return a.dis>b.dis;
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++) father[i]=i;
    for (int i=1; i<=m; i++)
        scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].dis);
    sort(edge+1,edge+1+m,comp);
    int flag; 
    for (int i=1; i<=m; i++)
    {
        if (judge(edge[i].from,edge[i].to)) {flag=i; break;}//此处应该是break而不是continue
        if (enemy[edge[i].from]) unionn(enemy[edge[i].from],edge[i].to);
        if (enemy[edge[i].to]) unionn(enemy[edge[i].to],edge[i].from);
        enemy[find(edge[i].from)]=edge[i].to;
        enemy[find(edge[i].to)]=edge[i].from;//是敌人 
    }
    printf("%d",edge[flag].dis);
    return 0;
}

二、二分做法

#include
#include
#include
using namespace std;
const int MAXN=20001;
const int MAXM=100001;
int n,m,ans;
int b[MAXN];//标记颜色 
struct Edge{
    int form,to,next,dis;
}edge[2*MAXM];
struct G{
    int x,y,z;
}g[MAXM];
bool comp(G a,G b) {return a.zint num_edge,head[MAXN];
void add_edge(int from,int to)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].to=to;
    head[from]=num_edge;
}

bool flag;
void dfs(int x,int fa)
{
    if (!flag) return;
    if (fa==0) b[x]=1;
    if (fa==1) b[x]=2;
    if (fa==2) b[x]=1;
    for (int i=head[x]; i!=0; i=edge[i].next)
    {
        if (!b[edge[i].to])
        {
            dfs(edge[i].to,b[x]);
        }
        else
        if (b[x]==b[edge[i].to]) {flag=false; return;}
    }
}

bool judge(int x)
{
    num_edge=0;
    memset(edge,0,sizeof(edge));
    memset(b,0,sizeof(b));
    memset(head,0,sizeof(head));
    for (int i=x+1; i<=m; i++)
    {
        add_edge(g[i].x,g[i].y); add_edge(g[i].y,g[i].x);
    }

    for (int i=1; i<=n; i++)
        if (!b[i])
        {
            flag=true; dfs(i,0);
            if (!flag) return false;
        }
    return true;
}

bool f;
void erfen(int l,int r)//二分边的编号 
{
    if (f) return;
    if (l==r) {ans=l; f=true; return;}
    int mid=(l+r)/2;
    if (judge(mid)) erfen(l,mid);
    else erfen(mid+1,r);
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1; i<=m; i++)
    {
        scanf("%d%d%d",&g[i].x,&g[i].y,&g[i].z);
    }
    if (m==1) {printf("0"); return 0;}
    sort(g+1,g+1+m,comp);
    erfen(1,m);
    printf("%d",g[ans].z);
    return 0;
}

你可能感兴趣的:(noip真题,并查集)