题目大意
排成一条直线的\(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;
}