Miku and Generals(二分图染色+可行性dp)

题意:

给你n个人,每个人有一个权值 a_i ​,(a_i​是可以被100整除的))现在需要你将n个人分成两组,有m个关系,a和b有关系代表a和b不能放在同一个组内,为了两组实力尽量平均,要你求两组权值差值最小时最大的值是哪一个

思路:

首先我们知道n个人必须全选分为两组,其次题目保证有解

因此我们很容易想到如果a->b,b->c,那么a一定和c要分在同一组内

这样我们就得到了很多个联通块

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define ll long long
using namespace std;
const int MAX=200005,INF = 0x3f3f3f3f;
struct node
{
    int v,nxt;
}e[450];
int head[220],dp[100000],vis[220],top,a[220],b[220];
int si;
void add(int u,int v)
{
    e[top].v=v;
    e[top].nxt=head[u];
    head[u]=top++;
}
void dfs(int x,int op)
{
    vis[x]=si+op;
    for(int i=head[x];i!=-1;i=e[i].nxt)
    {
        int v=e[i].v;
        if(vis[v]==0)
        {
            if(op==0) 
                dfs(v,1);
            else 
                dfs(v,0);
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        int num=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i]/=100;
            num+=a[i];
        }
        memset(head,-1,sizeof(head));
        top=0;
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        memset(vis,0,sizeof(vis));
        si=1;
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0)
            {
                dfs(i,0);
                si+=2;
            }
        }
        si--;
        memset(b,0,sizeof(b));
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            b[vis[i]]+=a[i];
        }
        int p=1;
        for(int i=1;i<= si;i+=2)
        {
            sum+=min(b[i],b[i+1]);
            b[p++]=abs(b[i]-b[i+1]);
        }
        memset(dp,0,sizeof(dp));
        m=num/2+num%2;
        m-=sum;
        dp[0]=0;
        for(int i=1;i<p;i++)
        {
            for(int j=m;j>=b[i];j--)
            {
                dp[j]=max(dp[j],dp[j-b[i]]+b[i]);
            }
        }
        int x=sum;
        if(dp[m]!= -1)
             x+=dp[m];
        int y=num-x;
        printf("%d\n",max(x,y)*100);
    }
    return 0;
}

 

posted @ 2020-02-07 20:18  Ldler  Views(151)  Comments(0Edit  收藏  举报