一.题意
你有n位同学,你想邀请他们中的一些人(可以都邀请上,也可以都不邀请)参加你的派对,他们之间有m对朋友关系(每个人可能有多个朋友)每对朋友会吃掉你的一块cake,但是你的厨师只能做出来偶数块cake,所以你的派对上只能出现偶数对朋友关系,所以你邀请到的人构成的朋友关系个数肯定是个偶数,这时候你可能就会不邀请班上的某些同学了,每位同学不被邀请的不开心值是ai,让你找到何种方案不开心值的和最小,求出这个不开心值的和,并输出。
输入:
T
n,m
a1~an
(然后下面是m对朋友关系)
输出:
最小的不开心值之和
二.思路
这个题里面含有一个小思维,首先我下了个结论,那就是作者要么排除0人要么排除1人要么排除2人不去邀请。
①排除0人:本来m就是偶数
②排除1人:m是奇数,这一个人所占有的朋友关系一定是奇数,这样m-这个人的朋友关系个数和 才是偶数。
③排除2人:m是奇数,这2个人每个人所占有的朋友关系一定是偶数(因为如果是奇数,那么他1个人就够了,不满足贪心思想),不但两人都是偶数,并且这两个人也要是朋友。这样去掉两人,去掉的朋友关系和才会是奇数(这里可以自己思考一下为什么)。
如果m是奇数,我们把①和②两种情况算出来的最小不开心值和再求个最小值就是最终答案,
具体实现方式看代码,有注释。
要是有更好的实现方式可以评论区call我OWO学习学习!
三.代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <map>
#include <vector>
using namespace std;
const int N = 1e5+10;
typedef pair<int, int> PII;
vector<int> v[N];
map<int,bool> st;
int a[N],cnt[N];
void solve()
{
st.clear();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
cnt[i]=0;
v[i].clear();//清空vector O(n)时间复杂度
}
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
v[a].push_back(b);//朋友关系
v[b].push_back(a);
cnt[a]++;//cnt[i] i有几个朋友
cnt[b]++;
}
if(m%2==0)
{
puts("0");
return;
}
int minone=0x3f3f3f3f;//情况①的最小不开心值
for(int i=1;i<=n;i++)
{
if(cnt[i]&1)
{
st[i]=1;
minone=min(a[i],minone);
}
}
int mintwo=0x3f3f3f3f;//情况①的最小不开心值和
for(int i=1;i<=n;i++)
{
st[i]=1;
if(cnt[i]&1) continue;
int siz=v[i].size();
for(int j=0;j<siz;j++)//枚举当前枚举的i的所有朋友满足(情况②的第二个限制条件)
{
if(st[v[i][j]]) continue;
if(cnt[v[i][j]]%2==0)
{
mintwo=min(a[i]+a[v[i][j]],mintwo);
}
}
}
cout<<min(mintwo,minone)<<endl;//①②取min
}
int main()
{
int T;
cin>>T;
while(T--)
{
solve();
}
}