大意不再赘述。
思路:在本题中,每个人都有两种状态,可以据此将两个人拆点成p0,p1,分别表示当选与落选。
i和j至少有一个人当选:i0->j1和j0->i1.
i和j至少有一个人落选:i1->j0,j1->i0.
i当选,j落选:i0->j0,j1->i1.
i落选,j当选:i1->j1,j0->i0.
大致就这么几种情况,分别连边之后判断有无点在同一个强连通分量里就OK。
拆点为2*x, 2*x+1, 前者表示落选,后者表示当选,由于数据从1开始,所以处理的时候自减1。
注意:数组开大点,顶点数组开的1010,TLE,边数组开的1000010会RE。
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
const int MAXN = 2010;
const int MAXM = 1000010;
const int INF = 0x3f3f3f3f;
struct Edge
{
int v, next, w;
}edge[MAXM*4];
int first[MAXN], dfn[MAXN], low[MAXN], stack[MAXN], ins[MAXN];
int belong[MAXN];
int n, m;
int cnt;
int scnt, tot, top;
inline void init()
{
cnt = 0;
scnt = tot = top = 0;
memset(first, -1, sizeof(first));
memset(ins, 0, sizeof(ins));
memset(dfn, 0, sizeof(dfn));
}
inline void read_graph(int u, int v)
{
edge[cnt].v = v;
edge[cnt].next = first[u], first[u] = cnt++;
}
void read_case()
{
init();
char c1, c2;
for(int i = 0; i < m; i++)
{
int x, y;
scanf(" %c%d %c%d", &c1, &x, &c2, &y);
--x;
--y;
if(c1 == '+')
{
if(c2 == '+') // + +
{
read_graph(2*x, 2*y+1);
read_graph(2*y, 2*x+1);
}
else // + -
{
read_graph(2*x, 2*y);
read_graph(2*y+1, 2*x+1);
}
}
else
{
if(c2 == '+') // - +
{
read_graph(2*x+1, 2*y+1);
read_graph(2*y, 2*x);
}
else // - -
{
read_graph(2*x+1, 2*y);
read_graph(2*y+1, 2*x);
}
}
}
}
void dfs(int u)
{
int v;
low[u] = dfn[u] = ++tot;
ins[u] = 1;
stack[top++] = u;
for(int e = first[u]; e != -1; e = edge[e].next)
{
v = edge[e].v;
if(!dfn[v])
{
dfs(v);
low[u] = min(low[u], low[v]);
}
else if(ins[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u])
{
scnt++;
do
{
v = stack[--top];
belong[v] = scnt;
ins[v] = 0;
}while(u != v);
}
}
void Tarjan()
{
for(int v = 0; v < 2*n; v++) if(!dfn[v])
dfs(v);
}
void solve()
{
Tarjan();
for(int i = 0; i < 2*n; i += 2)
{
if(belong[i] == belong[i+1])
{
printf("0\n");
return ;
}
}
printf("1\n");
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
read_case();
solve();
}
return 0;
}