Code forces Round #810 (Div. 2) B Party

这是一个关于编程竞赛的题目解析,主要涉及优化策略和贪心算法。题目要求在邀请俱乐部成员参加聚会时,使得未被邀请成员的不满意度总和最小,并且确保蛋糕分享的对数为偶数。解题思路包括判断朋友对数是否为偶数,以及在朋友对数为奇数时,如何选择剔除特定成员以达到条件。通过计算每个成员的不满意度和他们所在的朋友对数,确定最佳剔除策略。最后给出C++代码实现作为解决方案。
摘要由CSDN通过智能技术生成

题面

A club plans to hold a party and will invite some of its nn members. The nn members are identified by the numbers 1,2,…,n1,2,…,n. If member ii is not invited, the party will gain an unhappiness value of aiai.

There are mm pairs of friends among the nn members. As per tradition, if both people from a friend pair are invited, they will share a cake at the party. The total number of cakes eaten will be equal to the number of pairs of friends such that both members have been invited.

However, the club's oven can only cook two cakes at a time. So, the club demands that the total number of cakes eaten is an even number.

What is the minimum possible total unhappiness value of the party, respecting the constraint that the total number of cakes eaten is even?

Input

Each test contains multiple test cases. The first line contains the number of test cases tt (1≤t≤1041≤t≤104). The description of the test cases follows.

The first line of each test case contains two integers nn and mm (1≤n≤1051≤n≤105, 0≤m≤min(105,n(n−1)2)0≤m≤min(105,n(n−1)2)) — the number of club members and pairs of friends.

The second line of each test case contains nn integers a1,a2,…,ana1,a2,…,an (0≤ai≤1040≤ai≤104) — the unhappiness value array.

Each of the next mm lines contains two integers xx and yy (1≤x,y≤n1≤x,y≤n, x≠yx≠y) indicating that xx and yy are friends. Each unordered pair (x,y)(x,y) appears at most once in each test case.

It is guaranteed that both the sum of nn and the sum of mm over all test cases do not exceed 105105.

Output

For each test case, print a line containing a single integer – the minimum possible unhappiness value of a valid party.

简要题意:

共t组数据 每组数据给定n个人 以及对应的n个价值 再给出m对人 问如何取偶数对的人使得剩下的未被取出的人的总价值最小。

思路:

先从最直接的想法入手,就是对于每一种可能都遍历一遍,显然不行。为了缩小搜索的范围,可以反向考虑应该去掉其中的多少队。我们可以这样思考:先考虑去掉人数最少的情况,即从去掉1人开始搜寻可能的解,但是由于人数过多直接全部算一遍还是不可能的。因此我们还要思考一下去掉人时的策略。

通过观察我们可以发现,当m为偶数时是不需要去掉人的。而当m为奇数的时候,显然需要去掉奇数对的人可以满足条件。根据贪心的思想,去掉的人数是越小越好的的,定义第i个人价值为w[i],在去掉人数为k时,我们需要找出包含这k个人的对数为奇数的最小价值min(sum(w[1~k])),然后答案就在这些值之中了。当然前面已经说了,直接去掉1到n个人也是不可行的,但是其实我们可以发现最佳答案是在去掉1和2个人之间的,为什么呢。在这里我们先记录一下每个人所在的队的个数num[i],对于去掉一个人的情况,需要满足num[i]为奇数,然后寻找其最小值,对于去掉两个人的情况,需要满足num[i]+num[j]为偶数。(此时i和j必须在一队中,不然在一个人的情况就已经考虑了)考虑去掉三个人的情况,此时若三人都不在一组,就需要num[i]+num[j]+num[k]为奇数,那么其中必然存在奇数,不可能。 同理当其中有两人在同一组时,需要num[i]+num[j]+num[k]-1为奇数此时若num[i]+num[j]-1为偶数,num[k]就为奇数,反之也是一样,考虑num[i]+num[j]+num[k]-2为奇数 此时num[i]+num[j]-1和num[k]+num[j]-1中必有奇数,考虑num[i]+num[j]+num[k]-3为奇数

此时num[i]+num[j]-1和num[k]+num[j]-1和num[i]+num[k]-1中必有奇数

综上3个人以上的情况可以被1和2的最优替代掉,只需考虑1和2

接着就很简单了,记录一下每个数字的对数就好了

#include<bits/stdc++.h>
using namespace std;
int main()
{
   int t;
   cin>>t;
   while(t--)
   {
       int n,m;
       cin>>n>>m;
       int w[100010];
       int f[100010][2];
       int num[100010];
       //int sum[100010];
       for(int i=1;i<=n;i++)
       {
           scanf("%d",&w[i]);
           //sum[i]=w[i];
       }

       fill(num+1,num+n+1,0);
       for(int i=1;i<=m;i++)
       {
           scanf("%d %d",&f[i][0],&f[i][1]);
           num[f[i][0]]++;
           //sum[f[i][0]]+=w[f[i][1]];
           num[f[i][1]]++;
           //sum[f[i][1]]+=w[f[i][0]];
       }
       if(m%2==0)
       {
           printf("0\n");
       }
       else
       {
           int ans=0x3f3f3f3f;
           for(int i=1;i<=n;i++)
           {
               if(num[i]%2==1)
               {
                   if(w[i]<ans)
                    ans=w[i];
               }
           }

            for(int i=1;i<=m;i++)
            {
                if((num[f[i][0]]+num[f[i][1]])%2==0)
                {
                    //cout<<num[f[i][0]]<<" "<<num[f[i][1]]<<endl;
                    int x=w[f[i][0]]+w[f[i][1]];
                    if(x<ans)
                    {
                        ans=x;
                    }
                }

            }

           printf("%d\n",ans);
       }
   }
   return 0;
}


以上过程如有错误请在评论区指正

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值