本来是在看紫书的 然后书上的那个题想不出……心想着拿点见过的题先练练手
这道题应该在暑假集训的时候看过 有印象 但是我一定没做……
然后又要死了
题意:有n个点 然后n行表示每个节点的权值 再有m个双向路
求最大的异或值
分析:
1.判断图是否是连通图 ①继续 ②输出inpossble
2.判断图是欧拉路径还是欧拉回路
3.无论是欧拉路径还是欧拉回路只需要遍历一遍保存节点度数的数组就可以得出答案
前两步好办 并查集或者dfs判断是否连通 从度判断欧拉路的类型 第三步就涉及到数学了
如果是奇数则可贡献异或值 否则为0
抓破头皮想不通啊有没有 因为一个数异或其自己为0 所以如果一个节点经过了两次(偶数次)那这个节点的贡献值都为0
我们可以试一下这个degree的值 而经过的次数便是上边的(degree+1)/2
万物皆数学(我要死了orz)
其实私以为选定一个起点dfs模拟走遍所有的路枚举出来比大小应该也可以得到正确答案 但是这个时间估计会超时
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100005;
//vector<int>vv[maxn];
int a[maxn];//每个节点的权值
int b[maxn];//并查集
int d[maxn];//度
int find(int x)
{
if (x != b[x])
b[x] = find(b[x]);
return b[x];
}
void unio(int x,int y)
{
x = find(x);
y = find(y);
if (x != y)
b[x] = y;
}
int main()
{
int n, m;
int t;
cin >> t;
while (t--)
//while(1)
{
cin >> n >> m;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(d, 0, sizeof(d));
int flag = 1;
int ans = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
b[i] = i;
}
for (int i = 0; i < m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
// if (u == v)continue;
d[u]++;
d[v]++;
unio(u, v);
}
int cnt = 0;
for (int i = 1; i <= n; i++)
{
if (i == b[i])cnt++;
}
if (cnt == 1)//只有一个并查集
{
int c = 0;//奇点个数
for (int i = 1; i <= n; i++)
{
if (d[i] % 2)
c++;
}
if (c != 0 && c != 2)
{
cout << "Impossible" << endl;
continue;
}
for (int i = 1; i <= n; i++)
{
if ((d[i] + 1) / 2 % 2)
ans ^= a[i];
}
if (c == 0)//欧拉回路
{
int r = ans;
for (int i = 1; i <= n; i++)
{
ans=max(ans,r ^a[i]);
}
}
}
else
flag = 0;
cout << ans << endl;
}
return 0;
}
cin会超时
vector会爆内存
dfs求异或最大值铁定超时
还有我也知道为什么讨论说数据水了 刚刚看了一个博客 没有判断有没有独立的点在欧拉路外 所以甚至可以不用并查集