POJ 2454--Jersey Politics

32 篇文章 0 订阅

题意:有N = 3*K个城市,每个城市有1000头牛,每个城市的牛支持A或B,请将这N个城市分为3个地区,每个地区含有K个城市,且要使至少两个地区A的支持率高。

题解:首先将输入进行处理,保存每个城市支持数的差值,然后进行排序,因为一定有解,所以在前2*K个城市当中一定可以找到两个都满足要求的划分,则剩余K个城市直接划分为一个地区。

典型的组合数DFS,为了达到从2*N个牛中选择K个牛组成一个地区,可以按照地区中的城市号递增地选择城市。

剪枝:

  1. 剩下的城市数已经不能组成一个地区。
  2. 设sum[i]为从第i个到第2*K个城市的总差值,已经达到的差值为sumDiff,因为已经城市支持率为逆序,则剩下的城市要划分到地区1能获得最大的差值只能从beginCity一直连续取K-cliqueSize个城市,即若sumDiff+sum[beginCity]-sum[K-cliqueSize+beginCity] <= 0则地区1肯定不能满足要求。
  3. 类似的,剩下的城市要划分到地区0能获得的最大差值就是把从N逆序连续取K-cliqueSize个的城市全部给地区1,即sum[1]-(sumDiff+sum[N-K+cliqueSize+1]) <= 0则地区0肯定不能满足要求。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

struct node
{
    int num;
    int index;
    bool friend operator<(const node& a,const node& b)
    {
        return a.num > b.num;
    }
};

class solve
{
private:
    int K;
    int N;
    node* diffNum;
    int* sumDiffNum;        //从第i个到N的总差值
    char* clique;
public:
    solve(int k):K(k),N(3*k)
    {
        diffNum = new node[N+1];
        sumDiffNum = new int[N+2];
        clique = new char[N+1];
        memset(clique,0,sizeof(char)*(N+1));
        memset(sumDiffNum,0,sizeof(int)*(N+2));
        processIn();
        DFS(0,1,0);
        printClique(0);
    }
    ~solve()
    {
        delete[] diffNum;
        delete[] clique;
        delete[] sumDiffNum;
    }
    int processIn();
    int DFS(char cliqueSize,char beginCity,int sumDiff);
    int printClique(char cliqueFlag);
};

int solve::printClique(char cliqueFlag)
{
    if(cliqueFlag == 2)
        return 0;
    for(int i = 1;i <= N;i++)
    {
        if(clique[i] == cliqueFlag)
        {
            printf("%d\n",diffNum[i].index);
        }
    }
    printClique(cliqueFlag+1);
    return 0;
}

int solve::DFS(char cliqueSize,char beginCity,int sumDiff)
{
    if(cliqueSize == K)
    {
        if(sumDiff <= 0||sumDiffNum[1]-sumDiff <= 0)
            return 0;
        return 1;
    }
    if(cliqueSize+N-beginCity+1 < K||
       //剩下的城市数已不足以形成区
       sumDiff+sumDiffNum[beginCity]-sumDiffNum[K-cliqueSize+beginCity] <= 0||
       //剩下的地区1最大划分不满足要求
       sumDiffNum[1]-(sumDiff+sumDiffNum[N-K+cliqueSize+1]) <= 0)
       //剩下的地区0最大划分不满足要求
        return 0;
    for(int i = beginCity;i <= N;i++)
    {
        clique[i] = 1;
        if(DFS(cliqueSize+1,i+1,sumDiff+diffNum[i].num))
            return 1;
        clique[i] = 0;
    }
    return 0;
}

int solve::processIn()
{
    int tmpNum;
    for(int i = 1;i <= N;i++)
    {
        scanf("%d",&tmpNum);
        diffNum[i].num = 2*tmpNum-1000;
        diffNum[i].index = i;
    }
    sort(diffNum+1,diffNum+N+1);
    for(int i = 2*K+1;i <= N;i++)
        //直接输出的最小的K个城市
    {
        printf("%d\n",diffNum[i].index);
    }
    N -= K;
    for(int i = N;i >= 1;i--)
    {
        sumDiffNum[i] += sumDiffNum[i+1]+diffNum[i].num;
    }
    return 0;
}

int main()
{
    int k;
    while(~scanf("%d",&k))
    {
        solve poj_2454(k);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值