BZOJ 入门OJ 2006: [Noip模拟题]七天使的通讯

题目链接

题目大意

排成一条直线的\(n\)个点中存在\(m\)条边,每条边连接两个点,颜色或黑或白,皆在直线的同侧连接。要求所有相交的边颜色都不同,求是否存在一种方法对边进行染色。

数据范围

输入包含多组数据。
节点数\(n\)\(n \leq 5000\)
边数\(m\)\(n \leq 1000\)
数据组数\(T\)\(T \leq 10\)

分析

二分图判定裸题。

算法

将每个通道设为一个节点,先暴力判断每两条通道如果是同种颜色会不会相交,如果会相交就在这两个节点之间连无向边,说明它们不能为同种颜色(必须在二分图两边)。 然后对组成的无向图进行二分图判定(DFS染色),如果染色成功说明该图是一个二分图,即有解,否则无解。

参考代码

#include <bits/stdc++.h>
using namespace std;
#define rg register
 
const int MAXM = 1000 + 5;

struct Point
{
    int l, r;
}P[MAXM];

struct Edge
{
    int to, next;
}E[MAXM * MAXM / 2];
 
int n, m, wh;
int H[MAXM], cntE;
int Color[MAXM];
 
void Init()
{
    cntE = wh = 0;
    memset(Color, -1, sizeof Color);
    memset(H, 0, sizeof H);
    return ;
}

bool Check(int i,int j) 
{ 
    if(P[i].r <= P[j].l || P[j].r <= P[i].l) 
        return 0; 
    if(P[i].l <= P[j].l && P[i].r >= P[j].r) 
        return 0; 
    if(P[i].r <= P[j].r && P[i].l >= P[j].l) 
        return 0; 
    return 1; 
} 

inline void AddEdge(int u, int v)
{
    E[++cntE] = (Edge){v, H[u]};
    H[u] = cntE;
    return ;
}

void Input()
{
    scanf("%d%d", &n, &m);
    for(rg int i = 1; i <= m; ++i)
    {
        scanf("%d%d", &P[i].l, &P[i].r);
        if(P[i].l > P[i].r)
            swap(P[i].l, P[i].r);
        for(rg int j = 1; j < i; ++j)
        {
            if(Check(i, j))
            {
                AddEdge(i, j);
                AddEdge(j, i);
            }
        }
    }
    return ;
}

void Dfs(int x)
{
    if(wh)
        return ;
    for(rg int i = H[x]; i; i = E[i].next)
    {
        int& ne = E[i].to;
        if(Color[ne] == Color[x])
        {
            wh = 1;
            return ;
        }
        if(~Color[ne])
            continue;
        Color[ne] = Color[x] ^ 1;
        Dfs(ne);
    }
    return ;
}

bool Check()
{
    for(rg int i = 1; i <= m; ++i)
    {
        if(!~Color[i])
        {
            Color[i] = 0;
            Dfs(i);
            if(wh)
                return false;
        }
    }
    return true;
}
 
const char *Ans[] = {"non", "sane"};
 
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        Init();
        Input();
        printf("%s\n", Ans[Check()]);
    }
    return 0;
}
posted @ 2017-09-27 14:19  SkqLiao  阅读(206)  评论(0编辑  收藏  举报