Miku and Generals (西安邀请赛 二分图+背包)

题目 

https://nanti.jisuanke.com/t/39271

题意

给你n个权值 然你分成两组 使他们的权值和的差最小 ,其中有些点是相互矛盾的,不能分在同一组

思路

所有点都是100的倍数,可以直接 除以100

二分图染色 将矛盾的点缩为一个,假设每组小的分为一组,然后交换某些组,就相当于给小的一组加上他们的差值。

如果总和为2x 那么每组为x是最优的,每组小的和为y  那么只要找的小于(x-y)最大的即最优解 01背包即可

#include 

using namespace std;
struct node
{
    int v,nxt;
}e[450];
int head[220];
int vis[220];
int top;
int a[220];
int b[220];
int si;
int dp[100000];
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;
}

 

你可能感兴趣的:(#,二分图,#,背包)