1. 程式人生 > >洛谷1525 關押罪犯(並查集)(黑白染色)

洛谷1525 關押罪犯(並查集)(黑白染色)

題目

題解1

貪心+擴充套件域並查集 把怨氣值排序,大的當然要分配到兩個不同的監獄。 一個點拆成兩個點,分兩層,不同監獄連不同層。

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=20010,maxm=100010;

int n,m;
int fa[maxn*2];

struct U{int x,y,c;}a[maxm];
bool cmp(U u1,U u2)
{
    return u1.c>u2.c;
}

int find_fa(int x)
{
    if(x==fa[x]) return x;
    return find_fa(fa[x]);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n*2;i++) fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
    }
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        fa[find_fa(a[i].x)]=find_fa(a[i].y+n);
        fa[find_fa(a[i].x+n)]=find_fa(a[i].y);
        if(find_fa(a[i].x)==find_fa(a[i].y))
        {
            printf("%d\n",a[i].c);
            return 0;
        }
    }
    printf("0\n");
    return 0;
}

題解2

二分+黑白染色 答案顯然滿足二分性,問題轉變成判斷是否存在一種分配方案,使得所有大於mid的怨氣值的人被分在不同監獄。 刪掉所有邊權小於等於mid的邊,然後做黑白染色。如果染色中不發生衝突,那麼這個mid可行。 黑白染色就好像在說,與我連邊(怨氣值大於mid)的人都不能和我有一樣的顏色(監獄)。 這是利用了黑白染色可以判斷是否是二分圖的特點。其原理是判斷是否有奇環,如果一張圖有一個奇環,那麼所有的點都存在與某個奇環。

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=20010,maxm=100010;
int n,m;

struct E{int y,c,next;}e[maxm<<1];int len=0,last[maxn];
void ins(int x,int y,int c)
{
    e[++len]=(E){y,c,last[x]};last[x]=len;
}

int c[maxn];
bool dfs(int x,int color,int mid)
{
    c[x]=color;
    for(int k=last[x];k;k=e[k].next)
    {
        int y=e[k].y;
        if(e[k].c<=mid) continue;
        if(c[y] && c[y]==color) return false;
        else if(!c[y])
            if(!dfs(y,3-color,mid)) return false;
    }
    return true;
}

bool check(int mid)
{
    memset(c,0,sizeof(c));
    for(int i=1;i<=n;i++)//debug 列舉所有
        if(c[i]==0)
            if(!dfs(i,1,mid)) return false;
    return true;
}

int main()
{
    int mxc=0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);
        ins(x,y,c);ins(y,x,c);
        mxc=max(mxc,c);
    }
    
    int l=0,r=mxc,ans;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d",ans);
    return 0;
}