题目链接
http://uoj.ac/contest/51/problem/513
题解
好题。
考虑简化操作:
对于第二种操作,其实就可以等价于若干次单点操作,每次标记一个点,把和这个点相邻的边全部反转。即有用的操作只有 \(n\) 种。
对于第一种操作,众所周知一个无向图中所有的环都可以由若干个非树边覆盖的环异或得到。即有用的操作只有 \((m-n+1)\) 种。
这样我们可以得到一个异或方程组,变量数和方程数都为 \((m+1)\). 这也证明了为什么只要有解就能在 \((m+1)\) 次操作内出解。
时间复杂度 \(O(\frac{m^3}{\omega})\),期望得分 \(70\) 分。
考虑优化,通过欧拉回路不难证明一个子图可以用第一种操作消去当且仅当子图内每个点度都是偶数。
于是问题就变成了用第二种操作使得每个点度均为偶数。变量数量和方程数量都为 \(n\) 个。
时间复杂度 \(O(\frac{n^3}{\omega})\).
代码
#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define x first
#define y second
#define iter iterator
#define riter reversed_iterator
#define y1 Lorem_ipsum_dolor
using namespace std;
inline int read()
{
int x = 0,f = 1; char ch = getchar();
for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
return x*f;
}
const int mxN = 300;
bitset<mxN+3> a[mxN+3];
int n,m,en;
bool gauss()
{
for(int i=1; i<=n; i++)
{
if(!a[i][i])
{
for(int j=i+1; j<=n; j++) if(a[j][i]) {swap(a[j],a[i]);}
if(!a[i][i]) {continue;}
}
for(int j=i+1; j<=n; j++)
{
if(a[j][i]) {a[j] ^= a[i];}
}
}
for(int i=n; i>=1; i--)
{
int tmp = a[i][n+1];
for(int j=i+1; j<=n; j++) {tmp ^= (a[j][0]&a[i][j]);}
if(!a[i][i]&&tmp) {return false;}
a[i][0] = tmp;
}
return true;
}
int main()
{
int T = read(); while(T--)
{
n = read(),m = read();
for(int i=1; i<=m; i++)
{
int u = read(),v = read(),w = read();
a[u][u].flip(),a[v][v].flip(),a[u][v].flip(),a[v][u].flip();
if(w) {a[u][n+1].flip(),a[v][n+1].flip();}
}
bool ans = gauss();
if(ans) puts("yes"); else puts("no");
for(int i=1; i<=n; i++) a[i].reset();
}
return 0;
}